Reorganize source file hierarchy:

* Rename unity files
* Move some modules to new subdirectories
* Remove obsolete Visual Studio project files
* Remove obsolete coding style and TODO list
This commit is contained in:
Vinnie Falco
2014-06-03 14:48:34 -07:00
parent dda5fd7390
commit 558b914c64
213 changed files with 304 additions and 3704 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,135 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ARRAYALLOCATIONBASE_H_INCLUDED
#define BEAST_ARRAYALLOCATIONBASE_H_INCLUDED
#include <beast/HeapBlock.h>
namespace beast {
//==============================================================================
/**
Implements some basic array storage allocation functions.
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, SharedObjectArray
*/
template <class ElementType, class TypeOfCriticalSectionToUse>
class ArrayAllocationBase
: public TypeOfCriticalSectionToUse
{
public:
//==============================================================================
/** Creates an empty array. */
ArrayAllocationBase() noexcept
: numAllocated (0)
{
}
/** Destructor. */
~ArrayAllocationBase() noexcept
{
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
ArrayAllocationBase (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
: elements (static_cast <HeapBlock <ElementType>&&> (other.elements)),
numAllocated (other.numAllocated)
{
}
ArrayAllocationBase& operator= (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
{
elements = static_cast <HeapBlock <ElementType>&&> (other.elements);
numAllocated = other.numAllocated;
return *this;
}
#endif
//==============================================================================
/** 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 (const int numElements)
{
if (numAllocated != numElements)
{
if (numElements > 0)
elements.reallocate ((size_t) numElements);
else
elements.free_up();
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 (const int minNumElements)
{
if (minNumElements > numAllocated)
setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
bassert (numAllocated <= 0 || elements != nullptr);
}
/** Minimises the amount of storage allocated so that it's no more than
the given number of elements.
*/
void shrinkToNoMoreThan (const int maxNumElements)
{
if (maxNumElements < numAllocated)
setAllocatedSize (maxNumElements);
}
/** Swap the contents of two objects. */
void swapWith (ArrayAllocationBase <ElementType, TypeOfCriticalSectionToUse>& other) noexcept
{
elements.swapWith (other.elements);
std::swap (numAllocated, other.numAllocated);
}
//==============================================================================
HeapBlock <ElementType> elements;
int numAllocated;
};
} // beast
#endif // BEAST_ARRAYALLOCATIONBASE_H_INCLUDED

View File

@@ -0,0 +1,194 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_ELEMENTCOMPARATOR_H_INCLUDED
#define BEAST_ELEMENTCOMPARATOR_H_INCLUDED
namespace beast
{
#ifndef DOXYGEN
/** This is an internal helper class which converts a beast 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)
*/
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&);
};
#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)
{
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)
{
bassert (firstElement <= lastElement);
(void) 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
*/
template <class ElementType>
class DefaultElementComparator
{
private:
typedef ElementType ParameterType;
public:
static int compareElements (ParameterType first, ParameterType second)
{
return (first < second) ? -1 : ((second < first) ? 1 : 0);
}
};
} // beast
#endif

View File

@@ -0,0 +1,365 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_LINKEDLISTPOINTER_H_INCLUDED
#define BEAST_LINKEDLISTPOINTER_H_INCLUDED
namespace beast
{
//==============================================================================
/**
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
*/
template <class ObjectType>
class LinkedListPointer : public Uncopyable
{
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;
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
LinkedListPointer (LinkedListPointer&& other) noexcept
: item (other.item)
{
other.item = nullptr;
}
LinkedListPointer& operator= (LinkedListPointer&& other) noexcept
{
bassert (this != &other); // hopefully the compiler should make this situation impossible!
item = other.item;
other.item = nullptr;
return *this;
}
#endif
//==============================================================================
/** 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
{
LinkedListPointer* 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 (ObjectType* 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
{
LinkedListPointer* 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
{
const LinkedListPointer* 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 (ObjectType* 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)
{
bassert (newItem != nullptr);
bassert (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)
{
bassert (newItem != nullptr);
LinkedListPointer* 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
{
bassert (newItem != nullptr);
bassert (newItem->nextListItem == nullptr);
ObjectType* const 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)
{
LinkedListPointer* insertPoint = this;
for (ObjectType* 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
{
ObjectType* const 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 (LinkedListPointer* const 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)
{
ObjectType* const 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
{
LinkedListPointer* 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
{
bassert (destArray != nullptr);
for (ObjectType* 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 Uncopyable
{
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.
bassert (endOfListPointer.item == nullptr);
}
/** Appends an item to the list. */
void append (ObjectType* const newItem) noexcept
{
*endOfList = newItem;
endOfList = &(newItem->nextListItem);
}
private:
LinkedListPointer* endOfList;
};
private:
//==============================================================================
ObjectType* item;
};
} // beast
#endif // BEAST_LINKEDLISTPOINTER_H_INCLUDED

View File

@@ -0,0 +1,96 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SCOPEDVALUESETTER_H_INCLUDED
#define BEAST_SCOPEDVALUESETTER_H_INCLUDED
namespace beast
{
//==============================================================================
/**
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
*/
template <typename ValueType>
class ScopedValueSetter : public Uncopyable
{
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;
};
} // beast
#endif // BEAST_SCOPEDVALUESETTER_H_INCLUDED

184
beast/module/core/core.h Normal file
View File

@@ -0,0 +1,184 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CORE_H_INCLUDED
#define BEAST_CORE_H_INCLUDED
// TargetPlatform.h should not use anything from BeastConfig.h
#include <beast/Config.h>
#include <beast/config/ContractChecks.h>
#include <beast/module/core/system/BeforeBoost.h>
#include <beast/module/core/system/BoostIncludes.h>
#include <beast/module/core/system/FunctionalIncludes.h>
#if BEAST_MSVC
# pragma warning (disable: 4251) // (DLL build warning, must be disabled before pushing the warning state)
# pragma warning (push)
# pragma warning (disable: 4786) // (long class name warning)
# ifdef __INTEL_COMPILER
# pragma warning (disable: 1125)
# endif
#endif
//------------------------------------------------------------------------------
// New header-only library modeled more closely according to boost
#include <beast/SmartPtr.h>
#include <beast/StaticAssert.h>
#include <beast/Uncopyable.h>
#include <beast/Atomic.h>
#include <beast/Arithmetic.h>
#include <beast/ByteOrder.h>
#include <beast/HeapBlock.h>
#include <beast/Memory.h>
#include <beast/Intrusive.h>
#include <beast/Strings.h>
#include <beast/Threads.h>
#include <beast/utility/Debug.h>
#include <beast/utility/Error.h>
#include <beast/utility/Journal.h>
#include <beast/utility/LeakChecked.h>
#include <beast/utility/PropertyStream.h>
#include <beast/utility/StaticObject.h>
#include <beast/module/core/system/StandardIncludes.h>
namespace beast
{
class InputStream;
class OutputStream;
class FileInputStream;
class FileOutputStream;
} // beast
// Order matters, since headers don't have their own #include lines.
// Add new includes to the bottom.
#include <beast/module/core/system/Functional.h>
#include <beast/module/core/time/AtExitHook.h>
#include <beast/module/core/time/Time.h>
#include <beast/module/core/threads/ScopedLock.h>
#include <beast/module/core/threads/CriticalSection.h>
#include <beast/module/core/containers/ElementComparator.h>
// If the MSVC debug heap headers were included, disable
// the macros during the juce include since they conflict.
#ifdef _CRTDBG_MAP_ALLOC
#pragma push_macro("calloc")
#pragma push_macro("free")
#pragma push_macro("malloc")
#pragma push_macro("realloc")
#pragma push_macro("_recalloc")
#pragma push_macro("_aligned_free")
#pragma push_macro("_aligned_malloc")
#pragma push_macro("_aligned_offset_malloc")
#pragma push_macro("_aligned_realloc")
#pragma push_macro("_aligned_recalloc")
#pragma push_macro("_aligned_offset_realloc")
#pragma push_macro("_aligned_offset_recalloc")
#pragma push_macro("_aligned_msize")
#undef calloc
#undef free
#undef malloc
#undef realloc
#undef _recalloc
#undef _aligned_free
#undef _aligned_malloc
#undef _aligned_offset_malloc
#undef _aligned_realloc
#undef _aligned_recalloc
#undef _aligned_offset_realloc
#undef _aligned_offset_recalloc
#undef _aligned_msize
#endif
#include <beast/module/core/containers/ArrayAllocationBase.h>
#ifdef _CRTDBG_MAP_ALLOC
#pragma pop_macro("_aligned_msize")
#pragma pop_macro("_aligned_offset_recalloc")
#pragma pop_macro("_aligned_offset_realloc")
#pragma pop_macro("_aligned_recalloc")
#pragma pop_macro("_aligned_realloc")
#pragma pop_macro("_aligned_offset_malloc")
#pragma pop_macro("_aligned_malloc")
#pragma pop_macro("_aligned_free")
#pragma pop_macro("_recalloc")
#pragma pop_macro("realloc")
#pragma pop_macro("malloc")
#pragma pop_macro("free")
#pragma pop_macro("calloc")
#endif
#include <beast/module/core/containers/Array.h>
#include <beast/module/core/misc/Result.h>
#include <beast/module/core/text/StringArray.h>
#include <beast/module/core/memory/MemoryBlock.h>
#include <beast/module/core/files/File.h>
#include <beast/module/core/thread/MutexTraits.h>
#include <beast/module/core/diagnostic/FatalError.h>
#include <beast/module/core/text/LexicalCast.h>
#include <beast/module/core/maths/Math.h>
#include <beast/module/core/logging/Logger.h>
#include <beast/module/core/containers/LinkedListPointer.h>
#include <beast/module/core/maths/Random.h>
#include <beast/module/core/text/StringPairArray.h>
#include <beast/module/core/containers/ScopedValueSetter.h>
#include <beast/module/core/maths/Range.h>
#include <beast/module/core/files/DirectoryIterator.h>
#include <beast/module/core/streams/InputStream.h>
#include <beast/module/core/files/FileInputStream.h>
#include <beast/module/core/streams/InputSource.h>
#include <beast/module/core/streams/FileInputSource.h>
#include <beast/module/core/streams/OutputStream.h>
#include <beast/module/core/files/FileOutputStream.h>
#include <beast/module/core/files/FileSearchPath.h>
#include <beast/module/core/files/RandomAccessFile.h>
#include <beast/module/core/files/TemporaryFile.h>
#include <beast/module/core/logging/Logger.h>
#include <beast/module/core/memory/SharedSingleton.h>
#include <beast/module/core/misc/WindowsRegistry.h>
#include <beast/module/core/streams/MemoryOutputStream.h>
#include <beast/module/core/system/SystemStats.h>
#include <beast/module/core/diagnostic/SemanticVersion.h>
#include <beast/module/core/threads/DynamicLibrary.h>
#include <beast/module/core/threads/Process.h>
#include <beast/module/core/diagnostic/UnitTestUtilities.h>
#include <beast/module/core/diagnostic/MeasureFunctionCallTime.h>
#include <beast/module/core/thread/DeadlineTimer.h>
#include <beast/module/core/thread/Workers.h>
#if BEAST_MSVC
#pragma warning (pop)
#endif
#endif

View File

@@ -0,0 +1,237 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#if BEAST_INCLUDE_BEASTCONFIG
#include <BeastConfig.h>
#endif
//==============================================================================
#include <beast/module/core/native/BasicNativeHeaders.h>
#include <beast/module/core/core.h>
#include <locale>
#include <cctype>
#if ! BEAST_BSD
#include <sys/timeb.h>
#endif
#if ! BEAST_ANDROID
#include <cwctype>
#endif
#if BEAST_WINDOWS
#include <ctime>
#include <winsock2.h>
#include <ws2tcpip.h>
#if ! BEAST_MINGW
#include <Dbghelp.h>
#if ! BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
#pragma comment (lib, "DbgHelp.lib")
#endif
#endif
#if BEAST_MINGW
#include <ws2spi.h>
#endif
#else
#if BEAST_LINUX || BEAST_ANDROID
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <unistd.h>
#include <netinet/in.h>
#endif
#if BEAST_LINUX
#include <langinfo.h>
#endif
#include <pwd.h>
#include <fcntl.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <net/if.h>
#include <sys/ioctl.h>
#if ! BEAST_ANDROID && ! BEAST_BSD
#include <execinfo.h>
#endif
#endif
#if BEAST_MAC || BEAST_IOS
#include <xlocale.h>
#include <mach/mach.h>
#endif
#if BEAST_ANDROID
#include <android/log.h>
#endif
//------------------------------------------------------------------------------
// If the MSVC debug heap headers were included, disable
// the macros during the juce include since they conflict.
#ifdef _CRTDBG_MAP_ALLOC
#pragma push_macro("calloc")
#pragma push_macro("free")
#pragma push_macro("malloc")
#pragma push_macro("realloc")
#pragma push_macro("_recalloc")
#pragma push_macro("_aligned_free")
#pragma push_macro("_aligned_malloc")
#pragma push_macro("_aligned_offset_malloc")
#pragma push_macro("_aligned_realloc")
#pragma push_macro("_aligned_recalloc")
#pragma push_macro("_aligned_offset_realloc")
#pragma push_macro("_aligned_offset_recalloc")
#pragma push_macro("_aligned_msize")
#undef calloc
#undef free
#undef malloc
#undef realloc
#undef _recalloc
#undef _aligned_free
#undef _aligned_malloc
#undef _aligned_offset_malloc
#undef _aligned_realloc
#undef _aligned_recalloc
#undef _aligned_offset_realloc
#undef _aligned_offset_recalloc
#undef _aligned_msize
#endif
#include <beast/module/core/diagnostic/FatalError.cpp>
#include <beast/module/core/diagnostic/SemanticVersion.cpp>
#include <beast/module/core/diagnostic/UnitTestUtilities.cpp>
#include <beast/module/core/files/DirectoryIterator.cpp>
#include <beast/module/core/files/File.cpp>
#include <beast/module/core/files/FileInputStream.cpp>
#include <beast/module/core/files/FileOutputStream.cpp>
#include <beast/module/core/files/FileSearchPath.cpp>
#include <beast/module/core/files/RandomAccessFile.cpp>
#include <beast/module/core/files/TemporaryFile.cpp>
#include <beast/module/core/logging/Logger.cpp>
#include <beast/module/core/maths/Random.cpp>
#include <beast/module/core/memory/MemoryBlock.cpp>
#include <beast/module/core/misc/Result.cpp>
#include <beast/module/core/streams/FileInputSource.cpp>
#include <beast/module/core/streams/InputStream.cpp>
#include <beast/module/core/streams/MemoryOutputStream.cpp>
#include <beast/module/core/streams/OutputStream.cpp>
#include <beast/module/core/system/SystemStats.cpp>
#include <beast/module/core/text/LexicalCast.cpp>
#include <beast/module/core/text/StringArray.cpp>
#include <beast/module/core/text/StringPairArray.cpp>
#include <beast/module/core/thread/DeadlineTimer.cpp>
#include <beast/module/core/thread/Workers.cpp>
#include <beast/module/core/time/AtExitHook.cpp>
#include <beast/module/core/time/Time.cpp>
#if BEAST_MAC || BEAST_IOS
#include <beast/module/core/native/osx_ObjCHelpers.h>
#endif
#if BEAST_ANDROID
#include "native/android_JNIHelpers.h"
#endif
#if ! BEAST_WINDOWS
#include <beast/module/core/native/posix_SharedCode.h>
#endif
#if BEAST_MAC || BEAST_IOS
#include <beast/module/core/native/mac_Files.mm>
#include <beast/module/core/native/mac_Strings.mm>
#include <beast/module/core/native/mac_SystemStats.mm>
#include <beast/module/core/native/mac_Threads.mm>
#elif BEAST_WINDOWS
#include <beast/module/core/native/win32_ComSmartPtr.h>
#include <beast/module/core/native/win32_Files.cpp>
#include <beast/module/core/native/win32_Registry.cpp>
#include <beast/module/core/native/win32_SystemStats.cpp>
#include <beast/module/core/native/win32_Threads.cpp>
#elif BEAST_LINUX
#include <beast/module/core/native/linux_Files.cpp>
#include <beast/module/core/native/linux_SystemStats.cpp>
#include <beast/module/core/native/linux_Threads.cpp>
#elif BEAST_BSD
#include <beast/module/core/native/bsd_Files.cpp>
#include <beast/module/core/native/bsd_SystemStats.cpp>
#include <beast/module/core/native/bsd_Threads.cpp>
#elif BEAST_ANDROID
#include "native/android_Files.cpp"
#include "native/android_Misc.cpp"
#include "native/android_SystemStats.cpp"
#include "native/android_Threads.cpp"
#endif
// Has to be outside the beast namespace
extern "C" {
void beast_reportFatalError (char const* message, char const* fileName, int lineNumber)
{
if (beast::beast_isRunningUnderDebugger())
beast_breakDebugger;
beast::FatalError (message, fileName, lineNumber);
BEAST_ANALYZER_NORETURN
}
}
#ifdef _CRTDBG_MAP_ALLOC
#pragma pop_macro("calloc")
#pragma pop_macro("free")
#pragma pop_macro("malloc")
#pragma pop_macro("realloc")
#pragma pop_macro("_recalloc")
#pragma pop_macro("_aligned_free")
#pragma pop_macro("_aligned_malloc")
#pragma pop_macro("_aligned_offset_malloc")
#pragma pop_macro("_aligned_realloc")
#pragma pop_macro("_aligned_recalloc")
#pragma pop_macro("_aligned_offset_realloc")
#pragma pop_macro("_aligned_offset_recalloc")
#pragma pop_macro("_aligned_msize")
#endif
// Must be outside the namespace
#include <beast/module/core/system/BoostPlaceholdersFix.cpp>

View File

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

View File

@@ -0,0 +1,128 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
namespace beast {
//
// FatalError::Reporter
//
void FatalError::Reporter::onFatalError (
char const* message, char const* stackBacktrace, char const* filePath, int lineNumber)
{
String formattedMessage = formatMessage (
message, stackBacktrace, filePath, lineNumber);
reportMessage (formattedMessage);
}
void FatalError::Reporter::reportMessage (String& formattedMessage)
{
std::cerr << formattedMessage.toRawUTF8 ();
}
String FatalError::Reporter::formatMessage (
char const* message, char const* stackBacktrace, char const* filePath, int lineNumber)
{
String formattedMessage;
formattedMessage.preallocateBytes (16 * 1024);
formattedMessage << message;
if (filePath != nullptr && filePath [0] != 0)
{
formattedMessage << ", in " << formatFilePath (filePath)
<< " line " << String (lineNumber);
}
formattedMessage << newLine;
if (stackBacktrace != nullptr && stackBacktrace [0] != 0)
{
formattedMessage << "Stack:" << newLine;
formattedMessage << stackBacktrace;
}
return formattedMessage;
}
String FatalError::Reporter::formatFilePath (char const* filePath)
{
return filePath;
}
//------------------------------------------------------------------------------
FatalError::Reporter *FatalError::s_reporter;
/** Returns the current fatal error reporter. */
FatalError::Reporter* FatalError::getReporter ()
{
return s_reporter;
}
FatalError::Reporter* FatalError::setReporter (Reporter* reporter)
{
Reporter* const previous (s_reporter);
s_reporter = reporter;
return previous;
}
FatalError::FatalError (char const* message, char const* fileName, int lineNumber)
{
typedef CriticalSection LockType;
static LockType s_mutex;
std::lock_guard <LockType> lock (s_mutex);
String const backtraceString = SystemStats::getStackBacktrace ();
char const* const szStackBacktrace = backtraceString.toRawUTF8 ();
String const fileNameString = fileName;
char const* const szFileName = fileNameString.toRawUTF8 ();
Reporter* const reporter (s_reporter);
if (reporter != nullptr)
{
reporter->onFatalError (message, szStackBacktrace, szFileName, lineNumber);
}
Process::terminate ();
}
//------------------------------------------------------------------------------
class FatalError_test : public unit_test::suite
{
public:
void run ()
{
int shouldBeZero (1);
check_invariant (shouldBeZero == 0);
}
};
BEAST_DEFINE_TESTSUITE_MANUAL(FatalError,beast_core,beast);
} // beast

View File

@@ -0,0 +1,154 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CORE_FATALERROR_H_INCLUDED
#define BEAST_CORE_FATALERROR_H_INCLUDED
namespace beast
{
/** Signal a fatal error.
A fatal error indicates that the program has encountered an unexpected
situation and cannot continue safely. Reasons for raising a fatal error
would be to protect data integrity, prevent valuable resources from being
wasted, or to ensure that the user does not experience undefined behavior.
This function will end the process with exit code EXIT_FAILURE. Before
the process is terminated, a listener object gets notified so that the
client application can perform logging or emit further diagnostics.
*/
class FatalError : public Uncopyable
{
public:
struct Reporter
{
virtual ~Reporter () { }
/** Called when a fatal error is raised.
Because the program is likely in an inconsistent state, it is a
good idea to do as little as possible from within this function.
It will be called from the thread that raised the fatal error.
The default implementation of this function first calls
formatMessage to produce the string, then calls reportMessage
to report the results.
You can override this to perform custom formatting.
@note filePath may be a zero length string if identifying
information was stripped from the executable for security.
@note stackBacktrace will be a string with zero characters for
platforms for which which don't support stack crawls, or
when symbolic information is missing from the executable.
@param message The error message.
@param stackBackTrace The stack of the thread that raised the error.
@param filePath A full or partial path to the source file that raised the error.
@param lineNumber The line number in the source file.
*/
virtual void onFatalError (char const* message,
char const* stackBacktrace,
char const* filePath,
int lineNumber);
/** Called to report the message.
The default implementation simply writes this to standard error.
You can override this to perform additional things like logging
to a file or sending the message to another process.
@param formattedMessage The message to report.
*/
virtual void reportMessage (String& formattedMessage);
protected:
/** Called to format the message.
The default implementation calls formatFilePath to produce
a formatted file name, and then creates a suitable string
containing all of the information.
You can override this function to format your own messages.
@param message The message from the report.
@param stackBacktrace The stack backtrace from the report.
@param filePath The file path from the report.
@param lineNumber The line number from the report
*/
virtual String formatMessage (char const* message,
char const* stackBacktrace,
char const* filePath,
int lineNumber);
/** Call to reformat the file path.
Usually the file is a full path, which we really don't care
to see and can also be a security hole.
The default implementation removes most of the useless
directory components from the front.
You can override this to do a custom format on the file path.
*/
virtual String formatFilePath (char const* filePath);
};
/** Returns the current fatal error reporter. */
static Reporter* getReporter ();
/** Set the fatal error reporter.
Note that if a fatal error is raised during the construction of
objects with static storage duration, it might not be possible to
set the reporter before the error is raised. The solution is not
to use objects with static storage duration that have non-trivial
constructors, use SharedSingleton instead.
The default behavior when no reporter is set is to invoke
the base class version of Reporter::onFatalError.
If a reporter was previously set, this routine will do nothing.
@return The previous Reporter (Which may be null).
@see SharedSingleton, Reporter
*/
static Reporter* setReporter (Reporter* reporter);
/** Raise a fatal error.
If multiple threads raise an error, only one will succeed. The
other threads will be blocked before the process terminates.
@param message A null terminated string, which should come from a constant.
@param filePath Pass __FILE__ here.
@param lineNumber Pass __LINE__ here.
*/
FatalError (char const* message, char const* filePath, int lineNumber);
private:
static Reporter* s_reporter;
};
} // beast
#endif

View File

@@ -0,0 +1,85 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CORE_DIAGNOSTIC_MEASUREFUNCTIONCALLTIME_H_INCLUDED
#define BEAST_CORE_DIAGNOSTIC_MEASUREFUNCTIONCALLTIME_H_INCLUDED
namespace beast
{
/** Measures the speed of invoking a function. */
/** @{ */
template <typename Function>
double measureFunctionCallTime (Function f)
{
std::int64_t const startTime (Time::getHighResolutionTicks ());
f ();
return Time::highResolutionTicksToSeconds (
Time::getHighResolutionTicks () - startTime);
}
#if 0
template <typename Function,
typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6, typename P7, typename P8>
double measureFunctionCallTime (Function f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8)
{
std::int64_t const startTime (Time::getHighResolutionTicks ());
f (p1, p2, p3, p4, p5 ,p6 ,p7 ,p8);
return Time::highResolutionTicksToSeconds (
Time::getHighResolutionTicks () - startTime);
}
template <typename Function,
typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6, typename P7, typename P8>
double measureFunctionCallTime (Function f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8)
{
std::int64_t const startTime (Time::getHighResolutionTicks ());
f (p1, p2, p3, p4, p5 ,p6 ,p7 ,p8);
return Time::highResolutionTicksToSeconds (
Time::getHighResolutionTicks () - startTime);
}
template <typename Function,
typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6, typename P7, typename P8>
double measureFunctionCallTime (Function f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8)
{
std::int64_t const startTime (Time::getHighResolutionTicks ());
f (p1, p2, p3, p4, p5 ,p6 ,p7 ,p8);
return Time::highResolutionTicksToSeconds (
Time::getHighResolutionTicks () - startTime);
}
template <typename Function,
typename P1, typename P2, typename P3, typename P4,
typename P5, typename P6, typename P7, typename P8>
double measureFunctionCallTime (Function f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8)
{
std::int64_t const startTime (Time::getHighResolutionTicks ());
f (p1, p2, p3, p4, p5 ,p6 ,p7 ,p8);
return Time::highResolutionTicksToSeconds (
Time::getHighResolutionTicks () - startTime);
}
#endif
} // beast
#endif

View File

@@ -0,0 +1,521 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
namespace beast {
SemanticVersion::SemanticVersion ()
: majorVersion (0)
, minorVersion (0)
, patchVersion (0)
{
}
bool SemanticVersion::parse (String input)
{
// May not have leading or trailing whitespace
if (input.trim () != input)
return false;
// Must have major version number
if (! chopUInt (&majorVersion, std::numeric_limits <int>::max (), input))
return false;
if (! chop (".", input))
return false;
// Must have minor version number
if (! chopUInt (&minorVersion, std::numeric_limits <int>::max (), input))
return false;
if (! chop (".", input))
return false;
// Must have patch version number
if (! chopUInt (&patchVersion, std::numeric_limits <int>::max (), input))
return false;
// May have pre-release identifier list
if (chop ("-", input))
{
chopIdentifiers (&preReleaseIdentifiers, false, input);
// Must not be empty
if (preReleaseIdentifiers.size () <= 0)
return false;
}
// May have metadata identifier list
if (chop ("+", input))
{
chopIdentifiers (&metaData, true, input);
// Must not be empty
if (metaData.size () <= 0)
return false;
}
// May not have anything left
if (input.length () > 0)
return false;
return true;
}
String SemanticVersion::print () const
{
String s;
s << String (majorVersion) << "." << String (minorVersion) << "." << String (patchVersion);
if (preReleaseIdentifiers.size () > 0)
s << "-" << printIdentifiers (preReleaseIdentifiers);
if (metaData.size () > 0)
s << "+" << printIdentifiers (metaData);
return s;
}
int SemanticVersion::compare (SemanticVersion const& rhs) const noexcept
{
if (majorVersion > rhs.majorVersion)
return 1;
else if (majorVersion < rhs.majorVersion)
return -1;
if (minorVersion > rhs.minorVersion)
return 1;
else if (minorVersion < rhs.minorVersion)
return -1;
if (patchVersion > rhs.patchVersion)
return 1;
else if (patchVersion < rhs.patchVersion)
return -1;
if (isPreRelease () || rhs.isPreRelease ())
{
// Pre-releases have a lower precedence
if (isRelease () && rhs.isPreRelease ())
return 1;
else if (isPreRelease () && rhs.isRelease ())
return -1;
// Compare pre-release identifiers
for (int i = 0; i < bmax (preReleaseIdentifiers.size (), rhs.preReleaseIdentifiers.size ()); ++i)
{
// A larger list of identifiers has a higher precedence
if (i >= rhs.preReleaseIdentifiers.size ())
return 1;
else if (i >= preReleaseIdentifiers.size ())
return -1;
String const& left (preReleaseIdentifiers [i]);
String const& right (rhs.preReleaseIdentifiers [i]);
// Numeric identifiers have lower precedence
if (! isNumeric (left) && isNumeric (right))
return 1;
else if (isNumeric (left) && ! isNumeric (right))
return -1;
if (isNumeric (left))
{
bassert (isNumeric (right));
int const iLeft (left.getIntValue ());
int const iRight (right.getIntValue ());
if (iLeft > iRight)
return 1;
else if (iLeft < iRight)
return -1;
}
else
{
bassert (! isNumeric (right));
int result = left.compareLexicographically (right);
if (result != 0)
return result;
}
}
}
// metadata is ignored
return 0;
}
bool SemanticVersion::isNumeric (String const& s)
{
return String (s.getIntValue ()) == s;
}
bool SemanticVersion::chop (String const& what, String& input)
{
if (input.startsWith (what))
{
input = input.substring (what.length ());
return true;
}
return false;
}
String SemanticVersion::printIdentifiers (StringArray const& list)
{
String s;
if (list.size () > 0)
{
s << list [0];
for (int i = 1; i < list.size (); ++i)
s << "." << list [i];
}
return s;
}
bool SemanticVersion::chopUInt (int* value, int limit, String& input)
{
// Must not be empty
if (input.length () <= 0)
return false;
int firstNonDigit = 0;
for (; firstNonDigit < input.length (); ++firstNonDigit)
{
if (! CharacterFunctions::isDigit (input [firstNonDigit]))
break;
}
String const s = input.substring (0, firstNonDigit);
// Must not be empty
if (s.length () <= 0)
return false;
int const n = s.getIntValue ();
// Must not have leading zeroes
if (String (n) != s)
return false;
// Must not be out of range
if (n < 0 || n > limit)
return false;
input = input.substring (s.length ());
*value = n;
return true;
}
bool SemanticVersion::chopIdentifier (String* value, bool allowLeadingZeroes, String& input)
{
// Must not be empty
if (input.length () <= 0)
return false;
// Must not have a leading 0
if (! allowLeadingZeroes && input [0] == '0')
return false;
// Find the first character that cannot be part of an identifier
int i;
for (i = 0; i < input.length (); ++i)
{
static char const* validSet =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-";
if (! String (validSet).contains (String::charToString (input [i])))
break;
}
// Must not be empty
if (i <= 0)
return false;
*value = input.substring (0, i);
input = input.substring (i);
return true;
}
bool SemanticVersion::chopIdentifiers (StringArray* value, bool allowLeadingZeroes, String& input)
{
if (input.length () <= 0)
return false;
for (;;)
{
String s;
if (! chopIdentifier (&s, allowLeadingZeroes, input))
return false;
value->add (s);
if (! chop (".", input))
break;
}
return true;
}
//------------------------------------------------------------------------------
class SemanticVersion_test: public unit_test::suite
{
public:
void checkPass (String const& input, bool shouldPass = true)
{
SemanticVersion v;
if (shouldPass )
{
expect (v.parse (input));
expect (v.print () == input);
}
else
{
expect (! v.parse (input));
}
}
void checkFail (String const& input)
{
checkPass (input, false);
}
// check input and input with appended metadata
void checkMeta (String const& input, bool shouldPass)
{
checkPass (input, shouldPass);
checkPass (input + "+a", shouldPass);
checkPass (input + "+1", shouldPass);
checkPass (input + "+a.b", shouldPass);
checkPass (input + "+ab.cd", shouldPass);
checkFail (input + "!");
checkFail (input + "+");
checkFail (input + "++");
checkFail (input + "+!");
checkFail (input + "+.");
checkFail (input + "+a.!");
}
void checkMetaFail (String const& input)
{
checkMeta (input, false);
}
// check input, input with appended release data,
// input with appended metadata, and input with both
// appended release data and appended metadata
//
void checkRelease (String const& input, bool shouldPass = true)
{
checkMeta (input, shouldPass);
checkMeta (input + "-1", shouldPass);
checkMeta (input + "-a", shouldPass);
checkMeta (input + "-a1", shouldPass);
checkMeta (input + "-a1.b1", shouldPass);
checkMeta (input + "-ab.cd", shouldPass);
checkMeta (input + "--", shouldPass);
checkMetaFail (input + "+");
checkMetaFail (input + "!");
checkMetaFail (input + "-");
checkMetaFail (input + "-!");
checkMetaFail (input + "-.");
checkMetaFail (input + "-a.!");
checkMetaFail (input + "-0.a");
}
// Checks the major.minor.version string alone and with all
// possible combinations of release identifiers and metadata.
//
void check (String const& input, bool shouldPass = true)
{
checkRelease (input, shouldPass);
}
void negcheck (String const& input)
{
check (input, false);
}
void testParse ()
{
testcase ("parse");
check ("0.0.0");
check ("1.2.3");
check ("2147483647.2147483647.2147483647"); // max int
// negative values
negcheck ("-1.2.3");
negcheck ("1.-2.3");
negcheck ("1.2.-3");
// missing parts
negcheck ("");
negcheck ("1");
negcheck ("1.");
negcheck ("1.2");
negcheck ("1.2.");
negcheck (".2.3");
// whitespace
negcheck (" 1.2.3");
negcheck ("1 .2.3");
negcheck ("1.2 .3");
negcheck ("1.2.3 ");
// leading zeroes
negcheck ("01.2.3");
negcheck ("1.02.3");
negcheck ("1.2.03");
}
static StringArray ids ()
{
return StringArray ();
}
static StringArray ids (String const& s1)
{
StringArray v;
v.add (s1);
return v;
}
static StringArray ids (String const& s1, String const& s2)
{
StringArray v;
v.add (s1);
v.add (s2);
return v;
}
static StringArray ids (String const& s1, String const& s2, String const& s3)
{
StringArray v;
v.add (s1);
v.add (s2);
v.add (s3);
return v;
}
// Checks the decomposition of the input into appropriate values
void checkValues (String const& input,
int majorVersion,
int minorVersion,
int patchVersion,
StringArray const& preReleaseIdentifiers = StringArray (),
StringArray const& metaData = StringArray ())
{
SemanticVersion v;
expect (v.parse (input));
expect (v.majorVersion == majorVersion);
expect (v.minorVersion == minorVersion);
expect (v.patchVersion == patchVersion);
expect (v.preReleaseIdentifiers == preReleaseIdentifiers);
expect (v.metaData == metaData);
}
void testValues ()
{
checkValues ("0.1.2", 0, 1, 2);
checkValues ("1.2.3", 1, 2, 3);
checkValues ("1.2.3-rc1", 1, 2, 3, ids ("rc1"));
checkValues ("1.2.3-rc1.debug", 1, 2, 3, ids ("rc1", "debug"));
checkValues ("1.2.3-rc1.debug.asm", 1, 2, 3, ids ("rc1", "debug", "asm"));
checkValues ("1.2.3+full", 1, 2, 3, ids (), ids ("full"));
checkValues ("1.2.3+full.prod", 1, 2, 3, ids (), ids ("full", "prod"));
checkValues ("1.2.3+full.prod.x86", 1, 2, 3, ids (), ids ("full", "prod", "x86"));
checkValues ("1.2.3-rc1.debug.asm+full.prod.x86", 1, 2, 3,
ids ("rc1", "debug", "asm"), ids ("full", "prod", "x86"));
}
// makes sure the left version is less than the right
void checkLessInternal (String const& lhs, String const& rhs)
{
SemanticVersion left;
SemanticVersion right;
expect (left.parse (lhs));
expect (right.parse (rhs));
expect (left.compare (left) == 0);
expect (right.compare (right) == 0);
expect (left.compare (right) < 0);
expect (right.compare (left) > 0);
expect (left < right);
expect (right > left);
expect (left == left);
expect (right == right);
}
void checkLess (String const& lhs, String const& rhs)
{
checkLessInternal (lhs, rhs);
checkLessInternal (lhs + "+meta", rhs);
checkLessInternal (lhs, rhs + "+meta");
checkLessInternal (lhs + "+meta", rhs + "+meta");
}
void testCompare ()
{
checkLess ("1.0.0-alpha", "1.0.0-alpha.1");
checkLess ("1.0.0-alpha.1", "1.0.0-alpha.beta");
checkLess ("1.0.0-alpha.beta", "1.0.0-beta");
checkLess ("1.0.0-beta", "1.0.0-beta.2");
checkLess ("1.0.0-beta.2", "1.0.0-beta.11");
checkLess ("1.0.0-beta.11", "1.0.0-rc.1");
checkLess ("1.0.0-rc.1", "1.0.0");
checkLess ("0.9.9", "1.0.0");
}
void run ()
{
testParse ();
testValues ();
testCompare ();
}
};
BEAST_DEFINE_TESTSUITE(SemanticVersion,beast_core,beast);
} // beast

View File

@@ -0,0 +1,79 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SEMANTICVERSION_H_INCLUDED
#define BEAST_SEMANTICVERSION_H_INCLUDED
namespace beast
{
/** A Semantic Version number.
Identifies the build of a particular version of software using
the Semantic Versioning Specification described here:
http://semver.org/
*/
class SemanticVersion
{
public:
int majorVersion;
int minorVersion;
int patchVersion;
StringArray preReleaseIdentifiers;
StringArray metaData;
SemanticVersion ();
/** Parse a semantic version string.
The parsing is as strict as possible.
@return `true` if the string was parsed.
*/
bool parse (String input);
/** Produce a string from semantic version components. */
String print () const;
inline bool isRelease () const noexcept { return preReleaseIdentifiers.size () <= 0; }
inline bool isPreRelease () const noexcept { return ! isRelease (); }
/** Compare this against another version.
The comparison follows the rules as per the specification.
*/
int compare (SemanticVersion const& rhs) const noexcept;
inline bool operator== (SemanticVersion const& other) const noexcept { return compare (other) == 0; }
inline bool operator!= (SemanticVersion const& other) const noexcept { return compare (other) != 0; }
inline bool operator>= (SemanticVersion const& other) const noexcept { return compare (other) >= 0; }
inline bool operator<= (SemanticVersion const& other) const noexcept { return compare (other) <= 0; }
inline bool operator> (SemanticVersion const& other) const noexcept { return compare (other) > 0; }
inline bool operator< (SemanticVersion const& other) const noexcept { return compare (other) < 0; }
private:
static bool isNumeric (String const& s);
static String printIdentifiers (StringArray const& list);
static bool chop (String const& what, String& input);
static bool chopUInt (int* value, int limit, String& input);
static bool chopIdentifier (String* value, bool allowLeadingZeroes, String& input);
static bool chopIdentifiers (StringArray* value, bool preRelease, String& input);
};
} // beast
#endif

View File

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

View File

@@ -0,0 +1,105 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_UNITTESTUTILITIES_H_INCLUDED
#define BEAST_UNITTESTUTILITIES_H_INCLUDED
namespace beast {
namespace UnitTestUtilities {
/** Fairly shuffle an array pseudo-randomly.
*/
template <class T>
void repeatableShuffle (int const numberOfItems, T& arrayOfItems, Random& r)
{
for (int i = numberOfItems - 1; i > 0; --i)
{
int const choice = r.nextInt (i + 1);
std::swap (arrayOfItems [i], arrayOfItems [choice]);
}
}
template <class T>
void repeatableShuffle (int const numberOfItems, T& arrayOfItems, std::int64_t seedValue)
{
Random r (seedValue);
repeatableShuffle (numberOfItems, arrayOfItems, r);
}
//------------------------------------------------------------------------------
/** A block of memory used for test data.
*/
struct Payload
{
/** Construct a payload with a buffer of the specified maximum size.
@param maximumBytes The size of the buffer, in bytes.
*/
explicit Payload (int maxBufferSize)
: bufferSize (maxBufferSize)
, data (maxBufferSize)
{
}
/** Generate a random block of data within a certain size range.
@param minimumBytes The smallest number of bytes in the resulting payload.
@param maximumBytes The largest number of bytes in the resulting payload.
@param seedValue The value to seed the random number generator with.
*/
void repeatableRandomFill (int minimumBytes, int maximumBytes, std::int64_t seedValue) noexcept
{
bassert (minimumBytes >=0 && maximumBytes <= bufferSize);
Random r (seedValue);
bytes = minimumBytes + r.nextInt (1 + maximumBytes - minimumBytes);
bassert (bytes >= minimumBytes && bytes <= bufferSize);
for (int i = 0; i < bytes; ++i)
data [i] = static_cast <unsigned char> (r.nextInt ());
}
/** Compare two payloads for equality.
*/
bool operator== (Payload const& other) const noexcept
{
if (bytes == other.bytes)
{
return memcmp (data.getData (), other.data.getData (), bytes) == 0;
}
else
{
return false;
}
}
public:
int const bufferSize;
int bytes;
HeapBlock <char> data;
};
} // UnitTestUtilities
} // beast
#endif

View File

@@ -0,0 +1,159 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
static StringArray parseWildcards (const String& pattern)
{
StringArray s;
s.addTokens (pattern, ";,", "\"'");
s.trim();
s.removeEmptyStrings();
return s;
}
static bool fileMatches (const StringArray& wildCards, const String& filename)
{
for (int i = 0; i < wildCards.size(); ++i)
if (filename.matchesWildcard (wildCards[i], ! File::areFileNamesCaseSensitive()))
return true;
return false;
}
DirectoryIterator::DirectoryIterator (const File& directory, bool recursive,
const String& pattern, const int type)
: wildCards (parseWildcards (pattern)),
fileFinder (directory, (recursive || wildCards.size() > 1) ? "*" : pattern),
wildCard (pattern),
path (File::addTrailingSeparator (directory.getFullPathName())),
index (-1),
totalNumFiles (-1),
whatToLookFor (type),
isRecursive (recursive),
hasBeenAdvanced (false)
{
// you have to specify the type of files you're looking for!
bassert ((type & (File::findFiles | File::findDirectories)) != 0);
bassert (type > 0 && type <= 7);
}
DirectoryIterator::~DirectoryIterator()
{
}
bool DirectoryIterator::next()
{
return next (nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
}
bool DirectoryIterator::next (bool* const isDirResult, bool* const isHiddenResult, std::int64_t* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
hasBeenAdvanced = true;
if (subIterator != nullptr)
{
if (subIterator->next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly))
return true;
subIterator = nullptr;
}
String filename;
bool isDirectory, isHidden = false;
while (fileFinder.next (filename, &isDirectory,
(isHiddenResult != nullptr || (whatToLookFor & File::ignoreHiddenFiles) != 0) ? &isHidden : nullptr,
fileSize, modTime, creationTime, isReadOnly))
{
++index;
if (! filename.containsOnly ("."))
{
bool matches = false;
if (isDirectory)
{
if (isRecursive && ((whatToLookFor & File::ignoreHiddenFiles) == 0 || ! isHidden))
subIterator = new DirectoryIterator (File::createFileWithoutCheckingPath (path + filename),
true, wildCard, whatToLookFor);
matches = (whatToLookFor & File::findDirectories) != 0;
}
else
{
matches = (whatToLookFor & File::findFiles) != 0;
}
// if we're not relying on the OS iterator to do the wildcard match, do it now..
if (matches && (isRecursive || wildCards.size() > 1))
matches = fileMatches (wildCards, filename);
if (matches && (whatToLookFor & File::ignoreHiddenFiles) != 0)
matches = ! isHidden;
if (matches)
{
currentFile = File::createFileWithoutCheckingPath (path + filename);
if (isHiddenResult != nullptr) *isHiddenResult = isHidden;
if (isDirResult != nullptr) *isDirResult = isDirectory;
return true;
}
if (subIterator != nullptr)
return next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly);
}
}
return false;
}
const File& DirectoryIterator::getFile() const
{
if (subIterator != nullptr && subIterator->hasBeenAdvanced)
return subIterator->getFile();
// You need to call DirectoryIterator::next() before asking it for the file that it found!
bassert (hasBeenAdvanced);
return currentFile;
}
float DirectoryIterator::getEstimatedProgress() const
{
if (totalNumFiles < 0)
totalNumFiles = File (path).getNumberOfChildFiles (File::findFilesAndDirectories);
if (totalNumFiles <= 0)
return 0.0f;
const float detailedIndex = (subIterator != nullptr) ? index + subIterator->getEstimatedProgress()
: (float) index;
return detailedIndex / totalNumFiles;
}
} // beast

View File

@@ -0,0 +1,151 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_DIRECTORYITERATOR_H_INCLUDED
#define BEAST_DIRECTORYITERATOR_H_INCLUDED
namespace beast
{
//==============================================================================
/**
Searches through a 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 finding a large number of files, this is better than
using File::findChildFiles() because it doesn't block while it finds them
all, and this is more memory-efficient.
It can also guess how far it's got using a wildly inaccurate algorithm.
*/
class DirectoryIterator : LeakChecked <DirectoryIterator>, public Uncopyable
{
public:
//==============================================================================
/** 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
@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.
*/
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,
std::int64_t* 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:
//==============================================================================
class NativeIterator : LeakChecked <NativeIterator>, public Uncopyable
{
public:
NativeIterator (const File& directory, const String& wildCard);
~NativeIterator();
bool next (String& filenameFound,
bool* isDirectory, bool* isHidden, std::int64_t* fileSize,
Time* modTime, Time* creationTime, bool* isReadOnly);
class Pimpl;
private:
friend class DirectoryIterator;
friend class ScopedPointer<Pimpl>;
ScopedPointer<Pimpl> pimpl;
};
friend class ScopedPointer<NativeIterator::Pimpl>;
StringArray wildCards;
NativeIterator fileFinder;
String wildCard, path;
int index;
mutable int totalNumFiles;
const int whatToLookFor;
const bool isRecursive;
bool hasBeenAdvanced;
ScopedPointer <DirectoryIterator> subIterator;
File currentFile;
};
} // beast
#endif // BEAST_DIRECTORYITERATOR_H_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,966 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_FILE_H_INCLUDED
#define BEAST_FILE_H_INCLUDED
#include <beast/module/core/containers/Array.h>
#include <beast/module/core/memory/MemoryBlock.h>
#include <beast/module/core/misc/Result.h>
#include <beast/module/core/time/Time.h>
#include <beast/module/core/text/StringArray.h>
#include <beast/module/core/threads/CriticalSection.h>
namespace beast {
class FileInputStream;
class FileOutputStream;
//==============================================================================
/**
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
*/
class File
{
public:
//==============================================================================
/** Creates an (invalid) file object.
The file is initially set to an empty path, so getFullPath() will return
an empty string, and comparing the file to File::nonexistent will return
true.
You can use its operator= method to point it at a proper file.
*/
File() noexcept {}
/** 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() noexcept {}
/** 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);
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
File (File&&) noexcept;
File& operator= (File&&) noexcept;
#endif
//==============================================================================
/** This static constant is used for referring to an 'invalid' file. */
static File const& nonexistent ();
//==============================================================================
/** 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;
/** Returns the size of the file in bytes.
@returns the number of bytes in the file, or 0 if it doesn't exist.
*/
std::int64_t 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 (std::int64_t 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 (const String& 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 (const String& 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.
*/
std::int64_t 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 (String 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 (const String& siblingFileName) const;
//==============================================================================
/** Returns the directory that contains this file or directory.
e.g. for "/moose/fish/foo.txt" this will return "/moose/fish".
*/
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;
/** 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;
/** If this file is a link, this returns the file that it points to.
If this file isn't actually link, it'll just return itself.
*/
File getLinkedTarget() 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.
@returns true if the file has been created (or if it already existed).
@see createDirectory
*/
Result create() const;
/** Creates a new directory for this filename.
This will try to create the file as a directory, and fill 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.
@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.
@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() 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.
@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;
/** 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 inside a 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.
@param results an array to which File objects will be added for the
files that the search comes up with
@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 number of results that have been found
@see getNumberOfChildFiles, DirectoryIterator
*/
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, DirectoryIterator
*/
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.
@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
*/
FileInputStream* createInputStream() const;
/** Creates a stream to write to this file.
If the file exists, the stream that is returned will be positioned ready for
writing at the end of the file, so you might want to use deleteFile() first
to write to an empty file.
@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
*/
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.
Any single \\n characters in the string are replaced with \\r\\n before it is written.
@see replaceWithText
*/
bool appendText (const String& textToAppend,
bool asUnicode = false,
bool writeUnicodeHeaderBytes = false) 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;
/** 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
*/
std::int64_t 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
*/
std::int64_t 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::empty) 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.
*/
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".
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,
/** 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
};
/** Finds the location of a special type of file or directory, such as a home folder or
documents folder.
@see SpecialLocationType
*/
static File 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 (const String& 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 const beast_wchar separator;
/** The system-specific file separator character, as a string.
On Windows, this will be '\', on Mac/Linux, it'll be '/'
*/
static const String separatorString;
//==============================================================================
/** 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 (const String& 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);
#if BEAST_MAC || BEAST_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 BEAST_MAC || DOXYGEN
/** OSX ONLY - Adds this file to the OSX dock */
void addToDock() const;
#endif
#if BEAST_WINDOWS
/** Windows ONLY - Creates a win32 .LNK shortcut file that links to this file. */
bool createLink (const String& description, const File& linkFileToCreate) const;
#endif
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 setFileTimesInternal (std::int64_t m, std::int64_t a, std::int64_t c) const;
void getFileTimesInternal (std::int64_t& m, std::int64_t& a, std::int64_t& c) const;
bool setFileReadOnlyInternal (bool) const;
};
} // beast
#endif

View File

@@ -0,0 +1,95 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
std::int64_t beast_fileSetPosition (void* handle, std::int64_t pos);
//==============================================================================
FileInputStream::FileInputStream (const File& f)
: file (f),
fileHandle (nullptr),
currentPosition (0),
status (Result::ok()),
needToSeek (true)
{
openHandle();
}
FileInputStream::~FileInputStream()
{
closeHandle();
}
//==============================================================================
std::int64_t FileInputStream::getTotalLength()
{
return file.getSize();
}
int FileInputStream::read (void* buffer, int bytesToRead)
{
bassert (openedOk());
bassert (buffer != nullptr && bytesToRead >= 0);
if (needToSeek)
{
if (beast_fileSetPosition (fileHandle, currentPosition) < 0)
return 0;
needToSeek = false;
}
const size_t num = readInternal (buffer, (size_t) bytesToRead);
currentPosition += num;
return (int) num;
}
bool FileInputStream::isExhausted()
{
return currentPosition >= getTotalLength();
}
std::int64_t FileInputStream::getPosition()
{
return currentPosition;
}
bool FileInputStream::setPosition (std::int64_t pos)
{
bassert (openedOk());
if (pos != currentPosition)
{
pos = blimit ((std::int64_t) 0, getTotalLength(), pos);
needToSeek |= (currentPosition != pos);
currentPosition = pos;
}
return true;
}
} // beast

View File

@@ -0,0 +1,95 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_FILEINPUTSTREAM_H_INCLUDED
#define BEAST_FILEINPUTSTREAM_H_INCLUDED
namespace beast
{
//==============================================================================
/**
An input stream that reads from a local file.
@see InputStream, FileOutputStream, File::createInputStream
*/
class FileInputStream
: public InputStream
, LeakChecked <FileInputStream>
{
public:
//==============================================================================
/** Creates a FileInputStream.
@param fileToRead the file to read from - if the file can't be accessed for some
reason, then the stream will just contain no data
*/
explicit FileInputStream (const File& fileToRead);
/** Destructor. */
~FileInputStream();
//==============================================================================
/** 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(); }
//==============================================================================
std::int64_t getTotalLength();
int read (void* destBuffer, int maxBytesToRead);
bool isExhausted();
std::int64_t getPosition();
bool setPosition (std::int64_t pos);
private:
//==============================================================================
File file;
void* fileHandle;
std::int64_t currentPosition;
Result status;
bool needToSeek;
void openHandle();
void closeHandle();
size_t readInternal (void* buffer, size_t numBytes);
};
} // beast
#endif // BEAST_FILEINPUTSTREAM_H_INCLUDED

View File

@@ -0,0 +1,135 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
std::int64_t beast_fileSetPosition (void* handle, std::int64_t pos);
//==============================================================================
FileOutputStream::FileOutputStream (const File& f, const size_t bufferSizeToUse)
: file (f),
fileHandle (nullptr),
status (Result::ok()),
currentPosition (0),
bufferSize (bufferSizeToUse),
bytesInBuffer (0),
buffer (bmax (bufferSizeToUse, (size_t) 16))
{
openHandle();
}
FileOutputStream::~FileOutputStream()
{
flushBuffer();
flushInternal();
closeHandle();
}
std::int64_t FileOutputStream::getPosition()
{
return currentPosition;
}
bool FileOutputStream::setPosition (std::int64_t newPosition)
{
if (newPosition != currentPosition)
{
flushBuffer();
currentPosition = beast_fileSetPosition (fileHandle, newPosition);
}
return newPosition == currentPosition;
}
bool FileOutputStream::flushBuffer()
{
bool ok = true;
if (bytesInBuffer > 0)
{
ok = (writeInternal (buffer, bytesInBuffer) == (std::ptrdiff_t) bytesInBuffer);
bytesInBuffer = 0;
}
return ok;
}
void FileOutputStream::flush()
{
flushBuffer();
flushInternal();
}
bool FileOutputStream::write (const void* const src, const size_t numBytes)
{
bassert (src != nullptr && ((std::ptrdiff_t) numBytes) >= 0);
if (bytesInBuffer + numBytes < bufferSize)
{
memcpy (buffer + bytesInBuffer, src, numBytes);
bytesInBuffer += numBytes;
currentPosition += numBytes;
}
else
{
if (! flushBuffer())
return false;
if (numBytes < bufferSize)
{
memcpy (buffer + bytesInBuffer, src, numBytes);
bytesInBuffer += numBytes;
currentPosition += numBytes;
}
else
{
const std::ptrdiff_t bytesWritten = writeInternal (src, numBytes);
if (bytesWritten < 0)
return false;
currentPosition += bytesWritten;
return bytesWritten == (std::ptrdiff_t) numBytes;
}
}
return true;
}
bool FileOutputStream::writeRepeatedByte (std::uint8_t byte, size_t numBytes)
{
bassert (((std::ptrdiff_t) numBytes) >= 0);
if (bytesInBuffer + numBytes < bufferSize)
{
memset (buffer + bytesInBuffer, byte, numBytes);
bytesInBuffer += numBytes;
currentPosition += numBytes;
return true;
}
return OutputStream::writeRepeatedByte (byte, numBytes);
}
} // beast

View File

@@ -0,0 +1,115 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
#ifndef BEAST_FILEOUTPUTSTREAM_H_INCLUDED
#define BEAST_FILEOUTPUTSTREAM_H_INCLUDED
//==============================================================================
/**
An output stream that writes into a local file.
@see OutputStream, FileInputStream, File::createOutputStream
*/
class FileOutputStream
: public OutputStream
, LeakChecked <FileOutputStream>
{
public:
//==============================================================================
/** Creates a FileOutputStream.
If the file doesn't exist, it will first be created. If the file can't be
created or opened, the failedToOpen() method will return
true.
If the file already exists when opened, the stream's write-postion will
be set to the end of the file. To overwrite an existing file,
use File::deleteFile() before opening the stream, or use setPosition(0)
after it's opened (although this won't truncate the file).
@see TemporaryFile
*/
FileOutputStream (const File& fileToWriteTo,
size_t bufferSizeToUse = 16384);
/** Destructor. */
~FileOutputStream();
//==============================================================================
/** 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;
std::int64_t getPosition() override;
bool setPosition (std::int64_t) override;
bool write (const void*, size_t) override;
bool writeRepeatedByte (std::uint8_t byte, size_t numTimesToRepeat) override;
private:
//==============================================================================
File file;
void* fileHandle;
Result status;
std::int64_t currentPosition;
size_t bufferSize, bytesInBuffer;
HeapBlock <char> buffer;
void openHandle();
void closeHandle();
void flushInternal();
bool flushBuffer();
std::int64_t setPositionInternal (std::int64_t);
std::ptrdiff_t writeInternal (const void*, size_t);
};
} // beast
#endif

View File

@@ -0,0 +1,171 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
FileSearchPath::FileSearchPath()
{
}
FileSearchPath::FileSearchPath (const String& path)
{
init (path);
}
FileSearchPath::FileSearchPath (const FileSearchPath& other)
: directories (other.directories)
{
}
FileSearchPath::~FileSearchPath()
{
}
FileSearchPath& FileSearchPath::operator= (const String& path)
{
init (path);
return *this;
}
void FileSearchPath::init (const String& path)
{
directories.clear();
directories.addTokens (path, ";", "\"");
directories.trim();
directories.removeEmptyStrings();
for (int i = directories.size(); --i >= 0;)
directories.set (i, directories[i].unquoted());
}
int FileSearchPath::getNumPaths() const
{
return directories.size();
}
File FileSearchPath::operator[] (const int index) const
{
return File (directories [index]);
}
String FileSearchPath::toString() const
{
StringArray directories2 (directories);
for (int i = directories2.size(); --i >= 0;)
if (directories2[i].containsChar (';'))
directories2.set (i, directories2[i].quoted());
return directories2.joinIntoString (";");
}
void FileSearchPath::add (const File& dir, const int insertIndex)
{
directories.insert (insertIndex, dir.getFullPathName());
}
void FileSearchPath::addIfNotAlreadyThere (const File& dir)
{
for (int i = 0; i < directories.size(); ++i)
if (File (directories[i]) == dir)
return;
add (dir);
}
void FileSearchPath::remove (const int index)
{
directories.remove (index);
}
void FileSearchPath::addPath (const FileSearchPath& other)
{
for (int i = 0; i < other.getNumPaths(); ++i)
addIfNotAlreadyThere (other[i]);
}
void FileSearchPath::removeRedundantPaths()
{
for (int i = directories.size(); --i >= 0;)
{
const File d1 (directories[i]);
for (int j = directories.size(); --j >= 0;)
{
const File d2 (directories[j]);
if ((i != j) && (d1.isAChildOf (d2) || d1 == d2))
{
directories.remove (i);
break;
}
}
}
}
void FileSearchPath::removeNonExistentPaths()
{
for (int i = directories.size(); --i >= 0;)
if (! File (directories[i]).isDirectory())
directories.remove (i);
}
int FileSearchPath::findChildFiles (Array<File>& results,
const int whatToLookFor,
const bool searchRecursively,
const String& wildCardPattern) const
{
int total = 0;
for (int i = 0; i < directories.size(); ++i)
total += operator[] (i).findChildFiles (results,
whatToLookFor,
searchRecursively,
wildCardPattern);
return total;
}
bool FileSearchPath::isFileInPath (const File& fileToCheck,
const bool checkRecursively) const
{
for (int i = directories.size(); --i >= 0;)
{
const File d (directories[i]);
if (checkRecursively)
{
if (fileToCheck.isAChildOf (d))
return true;
}
else
{
if (fileToCheck.getParentDirectory() == d)
return true;
}
}
return false;
}
} // beast

View File

@@ -0,0 +1,163 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_FILESEARCHPATH_H_INCLUDED
#define BEAST_FILESEARCHPATH_H_INCLUDED
namespace beast
{
//==============================================================================
/**
Encapsulates a set of folders that make up a search path.
@see File
*/
class FileSearchPath : LeakChecked <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& other);
/** 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. */
void 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& other);
/** 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, adding any
matching files to the results array.
@param results an array to append the results to
@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
*/
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& path);
};
} // beast
#endif // BEAST_FILESEARCHPATH_H_INCLUDED

View File

@@ -0,0 +1,274 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
namespace beast {
RandomAccessFile::RandomAccessFile () noexcept
: fileHandle (nullptr)
, currentPosition (0)
{
}
RandomAccessFile::~RandomAccessFile ()
{
close ();
}
Result RandomAccessFile::open (File const& path, Mode mode)
{
close ();
return nativeOpen (path, mode);
}
void RandomAccessFile::close ()
{
if (isOpen ())
{
nativeFlush ();
nativeClose ();
}
}
Result RandomAccessFile::setPosition (FileOffset newPosition)
{
if (newPosition != currentPosition)
{
// VFALCO NOTE I dislike return from the middle but
// Result::ok() is showing up in the profile
//
return nativeSetPosition (newPosition);
}
return Result::ok ();
}
Result RandomAccessFile::read (void* buffer, ByteCount numBytes, ByteCount* pActualAmount)
{
return nativeRead (buffer, numBytes, pActualAmount);
}
Result RandomAccessFile::write (const void* data, ByteCount numBytes, ByteCount* pActualAmount)
{
bassert (data != nullptr && ((std::ptrdiff_t) numBytes) >= 0);
Result result (Result::ok ());
ByteCount amountWritten = 0;
result = nativeWrite (data, numBytes, &amountWritten);
if (result.wasOk ())
currentPosition += amountWritten;
if (pActualAmount != nullptr)
*pActualAmount = amountWritten;
return result;
}
Result RandomAccessFile::truncate ()
{
Result result = flush ();
if (result.wasOk ())
result = nativeTruncate ();
return result;
}
Result RandomAccessFile::flush ()
{
return nativeFlush ();
}
//------------------------------------------------------------------------------
class RandomAccessFile_test : public unit_test::suite
{
public:
enum
{
maxPayload = 8192
};
/* For this test we will create a file which consists of a fixed
number of variable length records. Each record is numbered sequentially
starting at 0. To calculate the position of each record we first build
a table of size/offset pairs using a pseudorandom number generator.
*/
struct Record
{
int index;
int bytes;
int offset;
};
typedef HeapBlock <Record> Records;
// Produce the pseudo-random set of records.
static void createRecords (HeapBlock <Record>& records,
int numRecords,
int maxBytes,
std::int64_t seedValue)
{
using namespace UnitTestUtilities;
Random r (seedValue);
records.malloc (numRecords);
int offset = 0;
for (int i = 0; i < numRecords; ++i)
{
int const bytes = r.nextInt (maxBytes) + 1;
records [i].index = i;
records [i].bytes = bytes;
records [i].offset = offset;
offset += bytes;
}
repeatableShuffle (numRecords, records, seedValue);
}
// Write all the records to the file.
// The payload is pseudo-randomly generated.
void writeRecords (RandomAccessFile& file,
int numRecords,
HeapBlock <Record> const& records,
std::int64_t seedValue)
{
using namespace UnitTestUtilities;
for (int i = 0; i < numRecords; ++i)
{
Payload p (records [i].bytes);
p.repeatableRandomFill (records [i].bytes,
records [i].bytes,
records [i].index + seedValue);
file.setPosition (records [i].offset);
Result result = file.write (p.data.getData (), p.bytes);
expect (result.wasOk (), "Should be ok");
}
}
// Read the records and verify the consistency.
void readRecords (RandomAccessFile& file,
int numRecords,
HeapBlock <Record> const& records,
std::int64_t seedValue)
{
using namespace UnitTestUtilities;
for (int i = 0; i < numRecords; ++i)
{
Record const& record (records [i]);
int const bytes = record.bytes;
Payload p1 (bytes);
Payload p2 (bytes);
p1.repeatableRandomFill (bytes, bytes, record.index + seedValue);
file.setPosition (record.offset);
Result result = file.read (p2.data.getData (), bytes);
expect (result.wasOk (), "Should be ok");
if (result.wasOk ())
{
p2.bytes = bytes;
expect (p1 == p2, "Should be equal");
}
}
}
// Perform the test at the given buffer size.
void testFile (int const numRecords)
{
using namespace UnitTestUtilities;
int const seedValue = 50;
std::stringstream ss;
ss << numRecords << " records";
testcase (ss.str());
// Calculate the path
File const path (File::createTempFile ("RandomAccessFile"));
// Create a predictable set of records
HeapBlock <Record> records (numRecords);
createRecords (records, numRecords, maxPayload, seedValue);
Result result (Result::ok ());
{
// Create the file
RandomAccessFile file;
result = file.open (path, RandomAccessFile::readWrite);
expect (result.wasOk (), "Should be ok");
if (result.wasOk ())
{
writeRecords (file, numRecords, records, seedValue);
readRecords (file, numRecords, records, seedValue);
repeatableShuffle (numRecords, records, seedValue);
readRecords (file, numRecords, records, seedValue);
}
}
if (result.wasOk ())
{
// Re-open the file in read only mode
RandomAccessFile file;
result = file.open (path, RandomAccessFile::readOnly);
expect (result.wasOk (), "Should be ok");
if (result.wasOk ())
{
readRecords (file, numRecords, records, seedValue);
}
}
}
void run ()
{
testFile (10000);
}
};
BEAST_DEFINE_TESTSUITE(RandomAccessFile,beast_core,beast);
} // beast

View File

@@ -0,0 +1,200 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_RANDOMACCESSFILE_H_INCLUDED
#define BEAST_RANDOMACCESSFILE_H_INCLUDED
namespace beast
{
/** Provides random access reading and writing to an operating system file.
This class wraps the underlying native operating system routines for
opening and closing a file for reading and/or writing, seeking within
the file, and performing read and write operations. There are also methods
provided for obtaining an input or output stream which will work with
the file.
@note All files are opened in binary mode. No text newline conversions
are performed.
@note None of these members are thread safe. The caller is responsible
for synchronization.
@see FileInputStream, FileOutputStream
*/
class RandomAccessFile : public Uncopyable, LeakChecked <RandomAccessFile>
{
public:
/** The type of an FileOffset.
This can be useful when writing templates.
*/
typedef std::int64_t FileOffset;
/** The type of a byte count.
This can be useful when writing templates.
*/
typedef size_t ByteCount;
/** The access mode.
@see open
*/
enum Mode
{
readOnly,
readWrite
};
//==============================================================================
/** Creates an unopened file object.
@see open, isOpen
*/
RandomAccessFile () noexcept;
/** Destroy the file object.
If the operating system file is open it will be closed.
*/
~RandomAccessFile ();
/** Determine if a file is open.
@return `true` if the operating system file is open.
*/
bool isOpen () const noexcept { return fileHandle != nullptr; }
/** Opens a file object.
The file is opened with the specified permissions. The initial
position is set to the beginning of the file.
@note If a file is already open, it will be closed first.
@param path The path to the file
@param mode The access permissions
@return An indication of the success of the operation.
@see Mode
*/
Result open (File const& path, Mode mode);
/** Closes the file object.
Any data that needs to be flushed will be written before the file is closed.
@note If no file is opened, this call does nothing.
*/
void close ();
/** Retrieve the @ref File associated with this object.
@return The associated @ref File.
*/
File const& getFile () const noexcept { return file; }
/** Get the current position.
The next read or write will take place from here.
@return The current position, as an absolute byte FileOffset from the begining.
*/
FileOffset getPosition () const noexcept { return currentPosition; }
/** Set the current position.
The next read or write will take place at this location.
@param newPosition The byte FileOffset from the beginning of the file to move to.
@return `true` if the operation was successful.
*/
Result setPosition (FileOffset newPosition);
/** Read data at the current position.
The caller is responsible for making sure that the memory pointed to
by `buffer` is at least as large as `bytesToRead`.
@note The file must have been opened with read permission.
@param buffer The memory to store the incoming data
@param numBytes The number of bytes to read.
@param pActualAmount Pointer to store the actual amount read, or `nullptr`.
@return `true` if all the bytes were read.
*/
Result read (void* buffer, ByteCount numBytes, ByteCount* pActualAmount = 0);
/** Write data at the current position.
The current position is advanced past the data written. If data is
written past the end of the file, the file size is increased on disk.
The caller is responsible for making sure that the memory pointed to
by `buffer` is at least as large as `bytesToWrite`.
@note The file must have been opened with write permission.
@param data A pointer to the data buffer to write to the file.
@param numBytes The number of bytes to write.
@param pActualAmount Pointer to store the actual amount written, or `nullptr`.
@return `true` if all the data was written.
*/
Result write (const void* data, ByteCount numBytes, ByteCount* pActualAmount = 0);
/** Truncate the file at the current position.
*/
Result truncate ();
/** Flush the output buffers.
This calls the operating system to make sure all data has been written.
*/
Result flush();
//==============================================================================
private:
// Some of these these methods are implemented natively on
// the corresponding platform.
//
// See beast_posix_SharedCode.h and beast_win32_Files.cpp
//
Result nativeOpen (File const& path, Mode mode);
void nativeClose ();
Result nativeSetPosition (FileOffset newPosition);
Result nativeRead (void* buffer, ByteCount numBytes, ByteCount* pActualAmount = 0);
Result nativeWrite (const void* data, ByteCount numBytes, ByteCount* pActualAmount = 0);
Result nativeTruncate ();
Result nativeFlush ();
private:
File file;
void* fileHandle;
FileOffset currentPosition;
};
} // beast
#endif

View File

@@ -0,0 +1,117 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
static File createTempFile (const File& parentDirectory, String name,
const String& suffix, const int optionFlags)
{
if ((optionFlags & TemporaryFile::useHiddenFile) != 0)
name = "." + name;
return parentDirectory.getNonexistentChildFile (name, suffix, (optionFlags & TemporaryFile::putNumbersInBrackets) != 0);
}
TemporaryFile::TemporaryFile (const String& suffix, const int optionFlags)
: temporaryFile (createTempFile (File::getSpecialLocation (File::tempDirectory),
"temp_" + String::toHexString (Random::getSystemRandom().nextInt()),
suffix, optionFlags))
{
}
TemporaryFile::TemporaryFile (const File& target, const int optionFlags)
: temporaryFile (createTempFile (target.getParentDirectory(),
target.getFileNameWithoutExtension()
+ "_temp" + String::toHexString (Random::getSystemRandom().nextInt()),
target.getFileExtension(), optionFlags)),
targetFile (target)
{
// If you use this constructor, you need to give it a valid target file!
bassert (targetFile != File::nonexistent ());
}
TemporaryFile::TemporaryFile (const File& target, const File& temporary)
: temporaryFile (temporary), targetFile (target)
{
}
TemporaryFile::~TemporaryFile()
{
if (! deleteTemporaryFile())
{
/* Failed to delete our temporary file! The most likely reason for this would be
that you've not closed an output stream that was being used to write to file.
If you find that something beyond your control is changing permissions on
your temporary files and preventing them from being deleted, you may want to
call TemporaryFile::deleteTemporaryFile() to detect those error cases and
handle them appropriately.
*/
bassertfalse;
}
}
//==============================================================================
bool TemporaryFile::overwriteTargetFileWithTemporary() const
{
// This method only works if you created this object with the constructor
// that takes a target file!
bassert (targetFile != File::nonexistent ());
if (temporaryFile.exists())
{
// Have a few attempts at overwriting the file before giving up..
for (int i = 5; --i >= 0;)
{
if (temporaryFile.moveFileTo (targetFile))
return true;
Thread::sleep (100);
}
}
else
{
// There's no temporary file to use. If your write failed, you should
// probably check, and not bother calling this method.
bassertfalse;
}
return false;
}
bool TemporaryFile::deleteTemporaryFile() const
{
// Have a few attempts at deleting the file before giving up..
for (int i = 5; --i >= 0;)
{
if (temporaryFile.deleteFile())
return true;
Thread::sleep (50);
}
return false;
}
} // beast

View File

@@ -0,0 +1,166 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_TEMPORARYFILE_H_INCLUDED
#define BEAST_TEMPORARYFILE_H_INCLUDED
namespace beast
{
//==============================================================================
/**
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...
ScopedPointer <FileOutputStream> out (temp.getFile().createOutputStream());
if (out != nullptr)
{
out->write ( ...etc )
out = nullptr; // (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
*/
class TemporaryFile : LeakChecked <TemporaryFile>, public Uncopyable
{
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::empty,
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 false, 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;
};
} // beast
#endif // BEAST_TEMPORARYFILE_H_INCLUDED

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
Logger::Logger() {}
Logger::~Logger()
{
// You're deleting this logger while it's still being used!
// Always call Logger::setCurrentLogger (nullptr) before deleting the active logger.
bassert (currentLogger != this);
}
Logger* Logger::currentLogger = nullptr;
void Logger::setCurrentLogger (Logger* const newLogger) noexcept { currentLogger = newLogger; }
Logger* Logger::getCurrentLogger() noexcept { return currentLogger; }
void Logger::writeToLog (const String& message)
{
if (currentLogger != nullptr)
currentLogger->logMessage (message);
else
outputDebugString (message);
}
#if BEAST_LOG_ASSERTIONS || BEAST_DEBUG
void logAssertion (const char* const filename, const int lineNum)
{
String m ("BEAST Assertion failure in ");
m << File::createFileWithoutCheckingPath (filename).getFileName() << ':' << lineNum;
#if BEAST_LOG_ASSERTIONS
Logger::writeToLog (m);
#else
BDBG (m);
#endif
}
#endif
} // beast

View File

@@ -0,0 +1,93 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_LOGGER_H_INCLUDED
#define BEAST_LOGGER_H_INCLUDED
namespace beast
{
//==============================================================================
/**
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.
*/
class 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 disable any logging.
*/
static void setCurrentLogger (Logger* newLogger) noexcept;
/** Returns the current logger, or nullptr if none has been set. */
static Logger* 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 writeToLog (const String& message);
//==============================================================================
/** Writes a message to the standard error stream.
This can be called directly, or by using the DBG() macro in
CompilerConfig.h (which will avoid calling the method in non-debug builds).
*/
static void 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;
};
} // beast
#endif // BEAST_LOGGER_H_INCLUDED

View File

@@ -0,0 +1,89 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MATH_H_INCLUDED
#define BEAST_MATH_H_INCLUDED
namespace beast
{
//
// Miscellaneous mathematical calculations
//
// Calculate the bin for a value given the bin size.
// This correctly handles negative numbers. For example
// if value == -1 then calc_bin returns -1.
template <typename Ty>
inline Ty calc_bin (Ty value, int size)
{
if (value >= 0)
return value / size;
else
return (value - size + 1) / size;
}
// Given a number and a bin size, this returns the first
// corresponding value of the bin associated with the given number.
// It correctly handles negative numbers. For example,
// if value == -1 then calc_bin always returns -size
template <typename Ty>
inline Ty calc_bin_start (Ty value, int size)
{
return calc_bin (value, size) * size;
}
template <class T>
inline T pi () noexcept
{
return 3.14159265358979;
}
template <class T>
inline T twoPi () noexcept
{
return 6.28318530717958;
}
template <class T>
inline T oneOverTwoPi () noexcept
{
return 0.1591549430918955;
}
template <class T, class U>
inline T degreesToRadians (U degrees)
{
return T (degrees * 0.0174532925199433);
}
template <class T, class U>
inline T radiansToDegrees (U radians)
{
T deg = T (radians * U (57.29577951308238));
if (deg < 0)
deg += 360;
return deg;
}
} // beast
#endif

View File

@@ -0,0 +1,155 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
namespace beast {
Random::Random (const std::int64_t seedValue) noexcept
: seed (seedValue)
{
nextInt (); // fixes a bug where the first int is always 0
}
Random::Random()
: seed (1)
{
setSeedRandomly();
}
Random::~Random() noexcept
{
}
void Random::setSeed (const std::int64_t newSeed) noexcept
{
seed = newSeed;
nextInt (); // fixes a bug where the first int is always 0
}
void Random::combineSeed (const std::int64_t seedValue) noexcept
{
seed ^= nextInt64() ^ seedValue;
}
void Random::setSeedRandomly()
{
static std::int64_t globalSeed = 0;
combineSeed (globalSeed ^ (std::int64_t) (std::intptr_t) this);
combineSeed (Time::getMillisecondCounter());
combineSeed (Time::getHighResolutionTicks());
combineSeed (Time::getHighResolutionTicksPerSecond());
combineSeed (Time::currentTimeMillis());
globalSeed ^= seed;
nextInt (); // fixes a bug where the first int is always 0
}
Random& Random::getSystemRandom() noexcept
{
static Random sysRand;
return sysRand;
}
//==============================================================================
int Random::nextInt() noexcept
{
seed = (seed * 0x5deece66dLL + 11) & 0xffffffffffffULL;
return (int) (seed >> 16);
}
int Random::nextInt (const int maxValue) noexcept
{
bassert (maxValue > 0);
return (int) ((((unsigned int) nextInt()) * (std::uint64_t) maxValue) >> 32);
}
std::int64_t Random::nextInt64() noexcept
{
return (((std::int64_t) nextInt()) << 32) | (std::int64_t) (std::uint64_t) (std::uint32_t) nextInt();
}
bool Random::nextBool() noexcept
{
return (nextInt() & 0x40000000) != 0;
}
float Random::nextFloat() noexcept
{
return static_cast <std::uint32_t> (nextInt()) / (float) 0xffffffff;
}
double Random::nextDouble() noexcept
{
return static_cast <std::uint32_t> (nextInt()) / (double) 0xffffffff;
}
void Random::fillBitsRandomly (void* const buffer, size_t bytes)
{
int* d = static_cast<int*> (buffer);
for (; bytes >= sizeof (int); bytes -= sizeof (int))
*d++ = nextInt();
if (bytes > 0)
{
const int lastBytes = nextInt();
memcpy (d, &lastBytes, bytes);
}
}
//==============================================================================
class Random_test : public unit_test::suite
{
public:
void run()
{
for (int j = 10; --j >= 0;)
{
Random r;
r.setSeedRandomly();
for (int i = 20; --i >= 0;)
{
expect (r.nextDouble() >= 0.0 && r.nextDouble() < 1.0);
expect (r.nextFloat() >= 0.0f && r.nextFloat() < 1.0f);
expect (r.nextInt (5) >= 0 && r.nextInt (5) < 5);
expect (r.nextInt (1) == 0);
int n = r.nextInt (50) + 1;
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
n = r.nextInt (0x7ffffffe) + 1;
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
}
}
}
};
BEAST_DEFINE_TESTSUITE(Random,beast_core,beast);
} // beast

View File

@@ -0,0 +1,128 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_RANDOM_H_INCLUDED
#define BEAST_RANDOM_H_INCLUDED
namespace beast
{
//==============================================================================
/**
A random number generator.
You can create a Random object and use it to generate a sequence of random numbers.
*/
class Random
{
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 (std::int64_t 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 64-bit random number.
@returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff
*/
std::int64_t nextInt64() noexcept;
/** Returns the next random floating-point number.
@returns a random value in the range 0 to 1.0
*/
float nextFloat() noexcept;
/** Returns the next random floating-point number.
@returns a random value in the range 0 to 1.0
*/
double nextDouble() noexcept;
/** Returns the next random boolean value.
*/
bool nextBool() noexcept;
/** Fills a block of memory with random values. */
void fillBitsRandomly (void* bufferToFill, size_t sizeInBytes);
//==============================================================================
/** Resets this Random object to a given seed value. */
void setSeed (std::int64_t newSeed) noexcept;
/** 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 (std::int64_t 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:
//==============================================================================
std::int64_t seed;
};
} // beast
#endif // BEAST_RANDOM_H_INCLUDED

View File

@@ -0,0 +1,263 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_RANGE_H_INCLUDED
#define BEAST_RANGE_H_INCLUDED
namespace beast
{
//==============================================================================
/** A general-purpose range object, that simply represents any linear range with
a start and end point.
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.
*/
template <typename ValueType>
class Range
{
public:
//==============================================================================
/** Constructs an empty range. */
Range() noexcept : start(), end()
{
}
/** Constructs a range with given start and end values. */
Range (const ValueType startValue, const ValueType endValue) noexcept
: start (startValue), end (bmax (startValue, endValue))
{
}
/** Constructs a copy of another range. */
Range (const Range& other) noexcept
: start (other.start), end (other.end)
{
}
/** Copies another range object. */
Range& operator= (Range other) noexcept
{
start = other.start;
end = other.end;
return *this;
}
/** Returns the range that lies between two positions (in either order). */
static Range between (const ValueType position1, const ValueType position2) noexcept
{
return position1 < position2 ? Range (position1, position2)
: Range (position2, position1);
}
/** Returns a range with the specified start position and a length of zero. */
static Range emptyRange (const ValueType start) noexcept
{
return Range (start, start);
}
//==============================================================================
/** Returns the start of the range. */
inline ValueType getStart() const noexcept { return start; }
/** Returns the length of the range. */
inline ValueType getLength() const noexcept { return end - start; }
/** Returns the end of the range. */
inline ValueType getEnd() const noexcept { return end; }
/** Returns true if the range has a length of zero. */
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.
*/
Range withStart (const ValueType newStart) const noexcept
{
return Range (newStart, bmax (newStart, end));
}
/** Returns a range with the same length as this one, but moved to have the given start position. */
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.
*/
Range withEnd (const ValueType newEnd) const noexcept
{
return Range (bmin (start, newEnd), newEnd);
}
/** Returns a range with the same length as this one, but moved to have the given end position. */
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 + bmax (ValueType(), newLength);
}
/** Returns a range with the same start as this one, but a different length.
Lengths less than zero are treated as zero.
*/
Range withLength (const ValueType newLength) const noexcept
{
return Range (start, start + newLength);
}
//==============================================================================
/** 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.
*/
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. */
Range operator- (const ValueType amountToSubtract) const noexcept
{
return Range (start - amountToSubtract, end - amountToSubtract);
}
bool operator== (Range other) const noexcept { return start == other.start && end == other.end; }
bool operator!= (Range other) const noexcept { return start != other.start || end != other.end; }
//==============================================================================
/** Returns true if the given position lies inside this range. */
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 blimit (start, end, value);
}
/** Returns true if the given range lies entirely inside this range. */
bool contains (Range other) const noexcept
{
return start <= other.start && end >= other.end;
}
/** Returns true if the given range intersects this one. */
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. */
Range getIntersectionWith (Range other) const noexcept
{
return Range (bmax (start, other.start),
bmin (end, other.end));
}
/** Returns the smallest range that contains both this one and the other one. */
Range getUnionWith (Range other) const noexcept
{
return Range (bmin (start, other.start),
bmax (end, other.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 (blimit (start, end - otherLen, rangeToConstrain.getStart()));
}
private:
//==============================================================================
ValueType start, end;
};
} // beast
#endif // BEAST_RANGE_H_INCLUDED

View File

@@ -0,0 +1,410 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
MemoryBlock::MemoryBlock() noexcept
: size (0)
{
}
MemoryBlock::MemoryBlock (const size_t initialSize, const bool initialiseToZero)
{
if (initialSize > 0)
{
size = initialSize;
data.allocate (initialSize, initialiseToZero);
}
else
{
size = 0;
}
}
MemoryBlock::MemoryBlock (const MemoryBlock& other)
: size (other.size)
{
if (size > 0)
{
bassert (other.data != nullptr);
data.malloc (size);
memcpy (data, other.data, size);
}
}
MemoryBlock::MemoryBlock (const void* const dataToInitialiseFrom, const size_t sizeInBytes)
: size (sizeInBytes)
{
bassert (((std::ptrdiff_t) sizeInBytes) >= 0);
if (size > 0)
{
bassert (dataToInitialiseFrom != nullptr); // non-zero size, but a zero pointer passed-in?
data.malloc (size);
if (dataToInitialiseFrom != nullptr)
memcpy (data, dataToInitialiseFrom, size);
}
}
MemoryBlock::~MemoryBlock() noexcept
{
}
MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other)
{
if (this != &other)
{
setSize (other.size, false);
memcpy (data, other.data, size);
}
return *this;
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
MemoryBlock::MemoryBlock (MemoryBlock&& other) noexcept
: data (static_cast <HeapBlock <char>&&> (other.data)),
size (other.size)
{
}
MemoryBlock& MemoryBlock::operator= (MemoryBlock&& other) noexcept
{
data = static_cast <HeapBlock <char>&&> (other.data);
size = other.size;
return *this;
}
#endif
//==============================================================================
bool MemoryBlock::operator== (const MemoryBlock& other) const noexcept
{
return matches (other.data, other.size);
}
bool MemoryBlock::operator!= (const MemoryBlock& other) const noexcept
{
return ! operator== (other);
}
bool MemoryBlock::matches (const void* dataToCompare, size_t dataSize) const noexcept
{
return size == dataSize
&& memcmp (data, dataToCompare, size) == 0;
}
//==============================================================================
// this will resize the block to this size
void MemoryBlock::setSize (const size_t newSize, const bool initialiseToZero)
{
if (size != newSize)
{
if (newSize <= 0)
{
data.free_up();
size = 0;
}
else
{
if (data != nullptr)
{
data.reallocate (newSize);
if (initialiseToZero && (newSize > size))
zeromem (data + size, newSize - size);
}
else
{
data.allocate (newSize, initialiseToZero);
}
size = newSize;
}
}
}
void MemoryBlock::ensureSize (const size_t minimumSize, const bool initialiseToZero)
{
if (size < minimumSize)
setSize (minimumSize, initialiseToZero);
}
void MemoryBlock::swapWith (MemoryBlock& other) noexcept
{
std::swap (size, other.size);
data.swapWith (other.data);
}
//==============================================================================
void MemoryBlock::fillWith (const std::uint8_t value) noexcept
{
memset (data, (int) value, size);
}
void MemoryBlock::append (const void* const srcData, const size_t numBytes)
{
if (numBytes > 0)
{
bassert (srcData != nullptr); // this must not be null!
const size_t oldSize = size;
setSize (size + numBytes);
memcpy (data + oldSize, srcData, numBytes);
}
}
void MemoryBlock::replaceWith (const void* const srcData, const size_t numBytes)
{
if (numBytes > 0)
{
bassert (srcData != nullptr); // this must not be null!
setSize (numBytes);
memcpy (data, srcData, numBytes);
}
}
void MemoryBlock::insert (const void* const srcData, const size_t numBytes, size_t insertPosition)
{
if (numBytes > 0)
{
bassert (srcData != nullptr); // this must not be null!
insertPosition = bmin (size, insertPosition);
const size_t trailingDataSize = size - insertPosition;
setSize (size + numBytes, false);
if (trailingDataSize > 0)
memmove (data + insertPosition + numBytes,
data + insertPosition,
trailingDataSize);
memcpy (data + insertPosition, srcData, numBytes);
}
}
void MemoryBlock::removeSection (const size_t startByte, const size_t numBytesToRemove)
{
if (startByte + numBytesToRemove >= size)
{
setSize (startByte);
}
else if (numBytesToRemove > 0)
{
memmove (data + startByte,
data + startByte + numBytesToRemove,
size - (startByte + numBytesToRemove));
setSize (size - numBytesToRemove);
}
}
void MemoryBlock::copyFrom (const void* const src, int offset, size_t num) noexcept
{
const char* d = static_cast<const char*> (src);
if (offset < 0)
{
d -= offset;
num += (size_t) -offset;
offset = 0;
}
if ((size_t) offset + num > size)
num = size - (size_t) offset;
if (num > 0)
memcpy (data + offset, d, num);
}
void MemoryBlock::copyTo (void* const dst, int offset, size_t num) const noexcept
{
char* d = static_cast<char*> (dst);
if (offset < 0)
{
zeromem (d, (size_t) -offset);
d -= offset;
num -= (size_t) -offset;
offset = 0;
}
if ((size_t) offset + num > size)
{
const size_t newNum = size - (size_t) offset;
zeromem (d + newNum, num - newNum);
num = newNum;
}
if (num > 0)
memcpy (d, data + offset, num);
}
String MemoryBlock::toString() const
{
return String (CharPointer_UTF8 (data), size);
}
//==============================================================================
int MemoryBlock::getBitRange (const size_t bitRangeStart, size_t numBits) const noexcept
{
int res = 0;
size_t byte = bitRangeStart >> 3;
size_t offsetInByte = bitRangeStart & 7;
size_t bitsSoFar = 0;
while (numBits > 0 && (size_t) byte < size)
{
const size_t bitsThisTime = bmin (numBits, 8 - offsetInByte);
const int mask = (0xff >> (8 - bitsThisTime)) << offsetInByte;
res |= (((data[byte] & mask) >> offsetInByte) << bitsSoFar);
bitsSoFar += bitsThisTime;
numBits -= bitsThisTime;
++byte;
offsetInByte = 0;
}
return res;
}
void MemoryBlock::setBitRange (const size_t bitRangeStart, size_t numBits, int bitsToSet) noexcept
{
size_t byte = bitRangeStart >> 3;
size_t offsetInByte = bitRangeStart & 7;
std::uint32_t mask = ~((((std::uint32_t) 0xffffffff) << (32 - numBits)) >> (32 - numBits));
while (numBits > 0 && (size_t) byte < size)
{
const size_t bitsThisTime = bmin (numBits, 8 - offsetInByte);
const std::uint32_t tempMask = (mask << offsetInByte) | ~((((std::uint32_t) 0xffffffff) >> offsetInByte) << offsetInByte);
const std::uint32_t tempBits = (std::uint32_t) bitsToSet << offsetInByte;
data[byte] = (char) (((std::uint32_t) data[byte] & tempMask) | tempBits);
++byte;
numBits -= bitsThisTime;
bitsToSet >>= bitsThisTime;
mask >>= bitsThisTime;
offsetInByte = 0;
}
}
//==============================================================================
void MemoryBlock::loadFromHexString (const String& hex)
{
ensureSize ((size_t) hex.length() >> 1);
char* dest = data;
String::CharPointerType t (hex.getCharPointer());
for (;;)
{
int byte = 0;
for (int loop = 2; --loop >= 0;)
{
byte <<= 4;
for (;;)
{
const beast_wchar c = t.getAndAdvance();
if (c >= '0' && c <= '9') { byte |= c - '0'; break; }
if (c >= 'a' && c <= 'z') { byte |= c - ('a' - 10); break; }
if (c >= 'A' && c <= 'Z') { byte |= c - ('A' - 10); break; }
if (c == 0)
{
setSize (static_cast <size_t> (dest - data));
return;
}
}
}
*dest++ = (char) byte;
}
}
//==============================================================================
static char const* const base64EncodingTable = ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+";
String MemoryBlock::toBase64Encoding() const
{
const size_t numChars = ((size << 3) + 5) / 6;
String destString ((unsigned int) size); // store the length, followed by a '.', and then the data.
const int initialLen = destString.length();
destString.preallocateBytes (sizeof (String::CharPointerType::CharType) * (size_t) initialLen + 2 + numChars);
String::CharPointerType d (destString.getCharPointer());
d += initialLen;
d.write ('.');
for (size_t i = 0; i < numChars; ++i)
d.write ((beast_wchar) (std::uint8_t) base64EncodingTable [getBitRange (i * 6, 6)]);
d.writeNull();
return destString;
}
bool MemoryBlock::fromBase64Encoding (const String& s)
{
const int startPos = s.indexOfChar ('.') + 1;
if (startPos <= 0)
return false;
const int numBytesNeeded = s.substring (0, startPos - 1).getIntValue();
setSize ((size_t) numBytesNeeded, true);
const int numChars = s.length() - startPos;
String::CharPointerType srcChars (s.getCharPointer());
srcChars += startPos;
int pos = 0;
for (int i = 0; i < numChars; ++i)
{
const char c = (char) srcChars.getAndAdvance();
for (int j = 0; j < 64; ++j)
{
if (base64EncodingTable[j] == c)
{
setBitRange ((size_t) pos, 6, j);
pos += 6;
break;
}
}
}
return true;
}
} // beast

View File

@@ -0,0 +1,274 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MEMORYBLOCK_H_INCLUDED
#define BEAST_MEMORYBLOCK_H_INCLUDED
#include <beast/utility/LeakChecked.h>
namespace beast {
//==============================================================================
/**
A class to hold a resizable block of raw data.
*/
class MemoryBlock : LeakChecked <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& other);
/** 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& other);
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
MemoryBlock (MemoryBlock&& other) noexcept;
MemoryBlock& operator= (MemoryBlock&& other) noexcept;
#endif
// Standard container interface
typedef char* iterator;
typedef char const* const_iterator;
inline iterator begin () noexcept { return static_cast <iterator> (getData ()); }
inline iterator end () noexcept { return addBytesToPointer (begin (), size); }
inline const_iterator cbegin () const noexcept { return static_cast <const_iterator> (getConstData ()); }
inline const_iterator cend () const noexcept { return addBytesToPointer (cbegin (), size); }
//==============================================================================
/** 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() const noexcept
{
return data;
}
/** Returns a void pointer to data as unmodifiable.
Note that the pointer returned will probably become invalid when the
block is resized.
*/
void const* getConstData() 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) const noexcept { return data [offset]; }
//==============================================================================
/** Returns the block's current allocated size, in bytes. */
size_t getSize() const noexcept { return size; }
/** Resizes the memory block.
This will try to keep as much of the block's current content as it can,
and can optionally be made to clear any new space that gets allocated at
the end of the block.
@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);
//==============================================================================
/** Fills the entire memory block with a repeated byte value.
This is handy for clearing a block of memory to zero.
*/
void fillWith (std::uint8_t 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 (const String& 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 that represent the binary contents of this block.
Uses a 64-bit encoding system to allow binary data to be turned into a string
of simple non-extended characters, e.g. for storage in XML.
@see fromBase64Encoding
*/
String toBase64Encoding() const;
/** Takes a string of encoded characters and turns it into binary data.
The string passed in must have been created by to64BitEncoding(), and this
block will be resized to recreate the original data block.
@see toBase64Encoding
*/
bool fromBase64Encoding (const String& encodedString);
private:
//==============================================================================
HeapBlock <char> data;
size_t size;
};
} // beast
#endif

View File

@@ -0,0 +1,202 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SHAREDSINGLETON_H_INCLUDED
#define BEAST_SHAREDSINGLETON_H_INCLUDED
#include <beast/threads/SpinLock.h>
#include <beast/smart_ptr/SharedPtr.h>
#include <beast/module/core/time/AtExitHook.h>
namespace beast
{
/** Thread-safe singleton which comes into existence on first use. Use this
instead of creating objects with static storage duration. These singletons
are automatically reference counted, so if you hold a pointer to it in every
object that depends on it, the order of destruction of objects is assured
to be correct.
Object Requirements:
DefaultConstructible
TriviallyDestructible (when lifetime == neverDestroyed)
Destructible
@class SharedSingleton
@ingroup beast_core
*/
/** @{ */
class SingletonLifetime
{
public:
// It would be nice if we didn't have to qualify the enumeration but
// Argument Dependent Lookup is inapplicable here because:
//
// "Base classes dependent on a template parameter aren't part of lookup."
// - ville
//
/** Construction options for SharedSingleton
@ingroup beast_core
*/
enum Lifetime
{
/** Created on first use, destroyed when the last reference is removed.
*/
createOnDemand,
/** The singleton is created on first use and persists until program exit.
*/
persistAfterCreation,
/** The singleton is created when needed and never destroyed.
This is useful for applications which do not have a clean exit.
*/
neverDestroyed
};
};
//------------------------------------------------------------------------------
/** Wraps object to produce a reference counted singleton. */
template <class Object>
class SharedSingleton
: public Object
, private SharedObject
{
public:
typedef SharedPtr <SharedSingleton <Object> > Ptr;
static Ptr get (SingletonLifetime::Lifetime lifetime
= SingletonLifetime::persistAfterCreation)
{
StaticData& staticData (getStaticData ());
SharedSingleton* instance = staticData.instance;
if (instance == nullptr)
{
std::lock_guard <LockType> lock (staticData.mutex);
instance = staticData.instance;
if (instance == nullptr)
{
bassert (lifetime == SingletonLifetime::createOnDemand || ! staticData.destructorCalled);
staticData.instance = &staticData.object;
new (staticData.instance) SharedSingleton (lifetime);
memoryBarrier();
instance = staticData.instance;
}
}
return instance;
}
// DEPRECATED LEGACY FUNCTION NAME
static Ptr getInstance (SingletonLifetime::Lifetime lifetime
= SingletonLifetime::persistAfterCreation)
{
return get (lifetime);
}
private:
explicit SharedSingleton (SingletonLifetime::Lifetime lifetime)
: m_lifetime (lifetime)
, m_exitHook (this)
{
if (m_lifetime == SingletonLifetime::persistAfterCreation ||
m_lifetime == SingletonLifetime::neverDestroyed)
this->incReferenceCount ();
}
~SharedSingleton ()
{
}
void onExit ()
{
if (m_lifetime == SingletonLifetime::persistAfterCreation)
this->decReferenceCount ();
}
void destroy () const
{
bool callDestructor;
// Handle the condition where one thread is releasing the last
// reference just as another thread is trying to acquire it.
//
{
StaticData& staticData (getStaticData ());
std::lock_guard <LockType> lock (staticData.mutex);
if (this->getReferenceCount() != 0)
{
callDestructor = false;
}
else
{
callDestructor = true;
staticData.instance = nullptr;
staticData.destructorCalled = true;
}
}
if (callDestructor)
{
bassert (m_lifetime != SingletonLifetime::neverDestroyed);
this->~SharedSingleton();
}
}
typedef SpinLock LockType;
// This structure gets zero-filled at static initialization time.
// No constructors are called.
//
class StaticData : public Uncopyable
{
public:
LockType mutex;
SharedSingleton* instance;
SharedSingleton object;
bool destructorCalled;
private:
StaticData();
~StaticData();
};
static StaticData& getStaticData ()
{
static std::uint8_t storage [sizeof (StaticData)];
return *(reinterpret_cast <StaticData*> (&storage [0]));
}
friend class SharedPtr <SharedSingleton>;
friend class AtExitMemberHook <SharedSingleton>;
SingletonLifetime::Lifetime m_lifetime;
AtExitMemberHook <SharedSingleton> m_exitHook;
};
//------------------------------------------------------------------------------
} // beast
#endif

View File

@@ -0,0 +1,83 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
Result::Result() noexcept {}
Result::Result (const String& message) noexcept
: errorMessage (message)
{
}
Result::Result (const Result& other)
: errorMessage (other.errorMessage)
{
}
Result& Result::operator= (const Result& other)
{
errorMessage = other.errorMessage;
return *this;
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
Result::Result (Result&& other) noexcept
: errorMessage (static_cast <String&&> (other.errorMessage))
{
}
Result& Result::operator= (Result&& other) noexcept
{
errorMessage = static_cast <String&&> (other.errorMessage);
return *this;
}
#endif
bool Result::operator== (const Result& other) const noexcept
{
return errorMessage == other.errorMessage;
}
bool Result::operator!= (const Result& other) const noexcept
{
return errorMessage != other.errorMessage;
}
Result Result::fail (const String& errorMessage) noexcept
{
return Result (errorMessage.isEmpty() ? "Unknown error" : errorMessage);
}
const String& Result::getErrorMessage() const noexcept
{
return errorMessage;
}
bool Result::wasOk() const noexcept { return errorMessage.isEmpty(); }
Result::operator bool() const noexcept { return errorMessage.isEmpty(); }
bool Result::failed() const noexcept { return errorMessage.isNotEmpty(); }
bool Result::operator!() const noexcept { return errorMessage.isNotEmpty(); }
} // beast

View File

@@ -0,0 +1,122 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_RESULT_H_INCLUDED
#define BEAST_RESULT_H_INCLUDED
namespace beast
{
/** 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
*/
class 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&);
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
Result (Result&&) noexcept;
Result& operator= (Result&&) noexcept;
#endif
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;
};
} // beast
#endif

View File

@@ -0,0 +1,124 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_WINDOWSREGISTRY_H_INCLUDED
#define BEAST_WINDOWSREGISTRY_H_INCLUDED
namespace beast
{
#if BEAST_WINDOWS || DOXYGEN
/**
Contains some static helper functions for manipulating the MS Windows registry
(Only available on Windows, of course!)
*/
class WindowsRegistry : public Uncopyable
{
public:
//==============================================================================
/** 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 getValue (const String& regValuePath,
const String& defaultValue = String::empty);
/** Returns a string from the WOW64 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 getValueWow64 (const String& regValuePath,
const String& defaultValue = String::empty);
/** 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 std::uint32_t getBinaryValue (const String& regValuePath, MemoryBlock& resultData);
/** 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 setValue (const String& regValuePath, const String& value);
/** 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 setValue (const String& regValuePath, std::uint32_t value);
/** 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 setValue (const String& regValuePath, std::uint64_t value);
/** 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 setValue (const String& regValuePath, const MemoryBlock& value);
/** Returns true if the given value exists in the registry. */
static bool valueExists (const String& regValuePath);
/** Returns true if the given value exists in the registry. */
static bool valueExistsWow64 (const String& regValuePath);
/** Deletes a registry value. */
static void deleteValue (const String& regValuePath);
/** Deletes a registry key (which is registry-talk for 'folder'). */
static void deleteKey (const String& regKeyPath);
/** 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.
*/
static bool registerFileAssociation (const String& fileExtension,
const String& symbolicDescription,
const String& fullDescription,
const File& targetExecutable,
int iconResourceNumber,
bool registerForCurrentUserOnly);
private:
WindowsRegistry();
};
#endif
} // beast
#endif // BEAST_WINDOWSREGISTRY_H_INCLUDED

View File

@@ -0,0 +1,239 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_BASICNATIVEHEADERS_H_INCLUDED
#define BEAST_BASICNATIVEHEADERS_H_INCLUDED
#include <beast/Config.h>
#undef T
//==============================================================================
#if BEAST_MAC || BEAST_IOS
#if BEAST_IOS
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#import <MobileCoreServices/MobileCoreServices.h>
#include <sys/fcntl.h>
#else
#define Point CarbonDummyPointName
#define Component CarbonDummyCompName
#import <Cocoa/Cocoa.h>
#import <CoreAudio/HostTime.h>
#undef Point
#undef Component
#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>
//==============================================================================
#elif BEAST_WINDOWS
#if BEAST_MSVC
#ifndef _CPPRTTI
#error "Beast requires RTTI!"
#endif
#ifndef _CPPUNWIND
#error "Beast requires RTTI!"
#endif
#pragma warning (push)
#pragma warning (disable : 4100 4201 4514 4312 4995)
#endif
#define STRICT 1
#define WIN32_LEAN_AND_MEAN 1
#ifndef _WIN32_WINNT
#if BEAST_MINGW
#define _WIN32_WINNT 0x0501
#else
#define _WIN32_WINNT 0x0600
#endif
#endif
#define _UNICODE 1
#define UNICODE 1
#ifndef _WIN32_IE
#define _WIN32_IE 0x0400
#endif
#include <windows.h>
#include <shellapi.h>
#include <tchar.h>
#include <stddef.h>
#include <ctime>
#include <wininet.h>
#include <nb30.h>
#include <iphlpapi.h>
#include <mapi.h>
#include <float.h>
#include <process.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <mmsystem.h>
#if BEAST_MINGW
#include <basetyps.h>
#else
#include <crtdbg.h>
#include <comutil.h>
#endif
#undef PACKED
#if BEAST_MSVC
#pragma warning (pop)
#pragma warning (4: 4511 4512 4100 /*4365*/) // (enable some warnings that are turned off in VC8)
#endif
#if BEAST_MSVC && ! BEAST_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 BEAST_LOAD_WINAPI_FUNCTION(dll, functionName, localFunctionName, returnType, params) \
typedef returnType (WINAPI *type##localFunctionName) params; \
type##localFunctionName localFunctionName = (type##localFunctionName) dll.getFunction (#functionName);
//==============================================================================
#elif BEAST_LINUX || BEAST_BSD
#include <sched.h>
#include <pthread.h>
#include <sys/time.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fnmatch.h>
#include <utime.h>
#include <pwd.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <sys/file.h>
#include <signal.h>
#include <stddef.h>
#if BEAST_BSD
#include <dirent.h>
#include <ifaddrs.h>
#include <net/if_dl.h>
#include <kvm.h>
#include <langinfo.h>
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/sysctl.h>
// This has to be in the global namespace
extern char** environ;
#else
#include <sys/dir.h>
#include <sys/vfs.h>
#include <sys/sysinfo.h>
#include <sys/prctl.h>
#endif
//==============================================================================
#elif BEAST_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>
#endif
// Need to clear various moronic redefinitions made by system headers..
#undef max
#undef min
#undef direct
#undef check
#endif // BEAST_BASICNATIVEHEADERS_H_INCLUDED

View File

@@ -0,0 +1,374 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
enum
{
U_ISOFS_SUPER_MAGIC = 5,
U_MSDOS_SUPER_MAGIC = 2,
U_NFS_SUPER_MAGIC = 1,
U_SMB_SUPER_MAGIC = 8
};
//==============================================================================
bool File::copyInternal (const File& dest) const
{
FileInputStream in (*this);
if (dest.deleteFile())
{
{
FileOutputStream out (dest);
if (out.failedToOpen())
return false;
if (out.writeFromInputStream (in, -1) == getSize())
return true;
}
dest.deleteFile();
}
return false;
}
void File::findFileSystemRoots (Array<File>& destArray)
{
destArray.add (File ("/"));
}
//==============================================================================
bool File::isOnCDRomDrive() const
{
struct statfs buf;
return statfs (getFullPathName().toUTF8(), &buf) == 0
&& buf.f_type == (short) U_ISOFS_SUPER_MAGIC;
}
bool File::isOnHardDisk() const
{
struct statfs buf;
if (statfs (getFullPathName().toUTF8(), &buf) == 0)
{
switch (buf.f_type)
{
case U_ISOFS_SUPER_MAGIC: // CD-ROM
case U_MSDOS_SUPER_MAGIC: // Probably floppy (but could be mounted FAT filesystem)
case U_NFS_SUPER_MAGIC: // Network NFS
case U_SMB_SUPER_MAGIC: // Network Samba
return false;
default:
// Assume anything else is a hard-disk (but note it could
// be a RAM disk. There isn't a good way of determining
// this for sure)
return true;
}
}
// Assume so if this fails for some reason
return true;
}
bool File::isOnRemovableDrive() const
{
bassertfalse; // XXX not implemented for FreeBSD!
return false;
}
bool File::isHidden() const
{
return getFileName().startsWithChar ('.');
}
//==============================================================================
namespace
{
File beast_readlink (const String& file, const File& defaultFile)
{
const size_t size = 8192;
HeapBlock<char> buffer;
buffer.malloc (size + 4);
const size_t numBytes = readlink (file.toUTF8(), buffer, size);
if (numBytes > 0 && numBytes <= size)
return File (file).getSiblingFile (String::fromUTF8 (buffer, (int) numBytes));
return defaultFile;
}
}
File File::getLinkedTarget() const
{
return beast_readlink (getFullPathName().toUTF8(), *this);
}
//==============================================================================
static File resolveXDGFolder (const char* const type, const char* const fallbackFolder)
{
StringArray confLines;
File ("~/.config/user-dirs.dirs").readLines (confLines);
for (int i = 0; i < confLines.size(); ++i)
{
const String line (confLines[i].trimStart());
if (line.startsWith (type))
{
// eg. resolve XDG_MUSIC_DIR="$HOME/Music" to /home/user/Music
const File f (line.replace ("$HOME", File ("~").getFullPathName())
.fromFirstOccurrenceOf ("=", false, false)
.trim().unquoted());
if (f.isDirectory())
return f;
}
}
return File (fallbackFolder);
}
const char* const* beast_argv = nullptr;
int beast_argc = 0;
File File::getSpecialLocation (const SpecialLocationType type)
{
switch (type)
{
case userHomeDirectory:
{
const char* homeDir = getenv ("HOME");
if (homeDir == nullptr)
{
struct passwd* const pw = getpwuid (getuid());
if (pw != nullptr)
homeDir = pw->pw_dir;
}
return File (CharPointer_UTF8 (homeDir));
}
case userDocumentsDirectory: return resolveXDGFolder ("XDG_DOCUMENTS_DIR", "~");
case userMusicDirectory: return resolveXDGFolder ("XDG_MUSIC_DIR", "~");
case userMoviesDirectory: return resolveXDGFolder ("XDG_VIDEOS_DIR", "~");
case userPicturesDirectory: return resolveXDGFolder ("XDG_PICTURES_DIR", "~");
case userDesktopDirectory: return resolveXDGFolder ("XDG_DESKTOP_DIR", "~/Desktop");
case userApplicationDataDirectory: return File ("~");
case commonApplicationDataDirectory: return File ("/var");
case globalApplicationsDirectory: return File ("/usr");
case tempDirectory:
{
File tmp ("/var/tmp");
if (! tmp.isDirectory())
{
tmp = "/tmp";
if (! tmp.isDirectory())
tmp = File::getCurrentWorkingDirectory();
}
return tmp;
}
case invokedExecutableFile:
if (beast_argv != nullptr && beast_argc > 0)
return File (CharPointer_UTF8 (beast_argv[0]));
// deliberate fall-through...
case currentExecutableFile:
case currentApplicationFile:
return beast_getExecutableFile();
case hostApplicationPath:
return beast_readlink ("/proc/self/exe", beast_getExecutableFile());
default:
bassertfalse; // unknown type?
break;
}
return File::nonexistent ();
}
//==============================================================================
String File::getVersion() const
{
return String::empty; // xxx not yet implemented
}
//==============================================================================
bool File::moveToTrash() const
{
if (! exists())
return true;
File trashCan ("~/.Trash");
if (! trashCan.isDirectory())
trashCan = "~/.local/share/Trash/files";
if (! trashCan.isDirectory())
return false;
return moveFileTo (trashCan.getNonexistentChildFile (getFileNameWithoutExtension(),
getFileExtension()));
}
//==============================================================================
class DirectoryIterator::NativeIterator::Pimpl : public Uncopyable
{
public:
Pimpl (const File& directory, const String& wildCard_)
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
wildCard (wildCard_),
dir (opendir (directory.getFullPathName().toUTF8()))
{
}
~Pimpl()
{
if (dir != nullptr)
closedir (dir);
}
bool next (String& filenameFound,
bool* const isDir, bool* const isHidden, std::int64_t* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
if (dir != nullptr)
{
const char* wildcardUTF8 = nullptr;
for (;;)
{
struct dirent* const de = readdir (dir);
if (de == nullptr)
break;
if (wildcardUTF8 == nullptr)
wildcardUTF8 = wildCard.toUTF8();
if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0)
{
filenameFound = CharPointer_UTF8 (de->d_name);
updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly);
if (isHidden != nullptr)
*isHidden = filenameFound.startsWithChar ('.');
return true;
}
}
}
return false;
}
private:
String parentDir, wildCard;
DIR* dir;
};
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
{
}
DirectoryIterator::NativeIterator::~NativeIterator()
{
}
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
bool* const isDir, bool* const isHidden, std::int64_t* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
}
//==============================================================================
static bool isFileExecutable (const String& filename)
{
beast_statStruct info;
return beast_stat (filename, info)
&& S_ISREG (info.st_mode)
&& access (filename.toUTF8(), X_OK) == 0;
}
bool Process::openDocument (const String& fileName, const String& parameters)
{
String cmdString (fileName.replace (" ", "\\ ",false));
cmdString << " " << parameters;
if ( cmdString.startsWithIgnoreCase ("file:")
|| File::createFileWithoutCheckingPath (fileName).isDirectory()
|| ! isFileExecutable (fileName))
{
// create a command that tries to launch a bunch of likely browsers
const char* const browserNames[] = { "xdg-open", "firefox", "seamonkey",
"chrome", "opera", "konqueror" };
StringArray cmdLines;
for (int i = 0; i < numElementsInArray (browserNames); ++i)
cmdLines.add (String (browserNames[i]) + " " + cmdString.trim().quoted());
cmdString = cmdLines.joinIntoString (" || ");
}
const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), 0 };
const int cpid = fork();
if (cpid == 0)
{
setsid();
// Child process
execve (argv[0], (char**) argv, environ);
exit (0);
}
return cpid >= 0;
}
void File::revealToUser() const
{
if (isDirectory())
startAsProcess();
else if (getParentDirectory().exists())
getParentDirectory().startAsProcess();
}
} // beast

View File

@@ -0,0 +1,356 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
// sysinfo() from sysinfo-bsd
// https://code.google.com/p/sysinfo-bsd/
/*
* Copyright (C) 2010 Kostas Petrikas, All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name(s) of the author(s) may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace beast
{
#define SI_LOAD_SHIFT 16
struct sysinfo {
long uptime; /* Seconds since boot */
unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
unsigned long totalram; /* Total usable main memory size */
unsigned long freeram; /* Available memory size */
unsigned long sharedram; /* Amount of shared memory */
unsigned long bufferram; /* Memory used by buffers */
unsigned long totalswap; /* Total swap space size */
unsigned long freeswap; /* swap space still available */
unsigned short procs; /* Number of current processes */
unsigned short pad; /* leaving this for linux compatability */
unsigned long totalhigh; /* Total high memory size */
unsigned long freehigh; /* Available high memory size */
unsigned int mem_unit; /* Memory unit size in bytes */
char _f[20-2*sizeof(long)-sizeof(int)]; /* leaving this for linux compatability */
};
#define NLOADS 3
#define UNIT_S 1024 /*Kb*/
#define R_IGNORE -1
/*the macros*/
#define R_ERROR(_EC) {if(_EC > R_IGNORE)errno = _EC; return -1;}
#define GETSYSCTL(name, var) getsysctl((char*)name, &(var), sizeof(var))
#define PAGE_2_UNIT(_PAGE) (((double)_PAGE * page_s) / UNIT_S)
/*sysctl wrapper*/
static int getsysctl(char *name, void *ptr, size_t len){
size_t nlen = len;
if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)
return -1;
if (nlen != len)
return -1;
return 0;
}
int sysinfo(struct sysinfo *info){
kvm_t *kvmh;
double load_avg[NLOADS];
int page_s = getpagesize();
if (info == NULL)
R_ERROR(EFAULT);
memset(info, 0, sizeof(struct sysinfo));
info -> mem_unit = UNIT_S;
/*kvm init*/
if ((kvmh = kvm_open(NULL, "/dev/null", "/dev/null",
O_RDONLY, "kvm_open")) == NULL)
R_ERROR(0);
/*load averages*/
if (kvm_getloadavg(kvmh, load_avg, NLOADS) == -1)
R_ERROR(0);
info -> loads[0] = (u_long)((float)load_avg[0] * USHRT_MAX);
info -> loads[1] = (u_long)((float)load_avg[1] * USHRT_MAX);
info -> loads[2] = (u_long)((float)load_avg[2] * USHRT_MAX);
/*swap space*/
struct kvm_swap k_swap;
if (kvm_getswapinfo(kvmh, &k_swap, 1, 0) == -1)
R_ERROR(0);
info -> totalswap =
(u_long)PAGE_2_UNIT(k_swap.ksw_total);
info -> freeswap = info -> totalswap -
(u_long)PAGE_2_UNIT(k_swap.ksw_used);
/*processes*/
int n_procs;
if (kvm_getprocs(kvmh, KERN_PROC_ALL, 0, &n_procs) == NULL)
R_ERROR(0);
info -> procs = (u_short)n_procs;
/*end of kvm session*/
if (kvm_close(kvmh) == -1)
R_ERROR(0);
/*uptime*/
struct timespec ts;
if (clock_gettime(CLOCK_UPTIME, &ts) == -1)
R_ERROR(R_IGNORE);
info -> uptime = (long)ts.tv_sec;
/*ram*/
int total_pages,
free_pages,
active_pages,
inactive_pages;
u_long shmmax;
if (GETSYSCTL("vm.stats.vm.v_page_count", total_pages) == -1)
R_ERROR(R_IGNORE);
if (GETSYSCTL("vm.stats.vm.v_free_count", free_pages) == -1)
R_ERROR(R_IGNORE);
if (GETSYSCTL("vm.stats.vm.v_active_count", active_pages) == -1)
R_ERROR(R_IGNORE);
if (GETSYSCTL("vm.stats.vm.v_inactive_count", inactive_pages) == -1)
R_ERROR(R_IGNORE);
if (GETSYSCTL("kern.ipc.shmmax", shmmax) == -1)
R_ERROR(R_IGNORE);
info -> totalram = (u_long)PAGE_2_UNIT(total_pages);
info -> freeram = (u_long)PAGE_2_UNIT(free_pages);
info -> bufferram = (u_long)PAGE_2_UNIT(active_pages);
info -> sharedram = shmmax / UNIT_S;
/*high mem (todo)*/
info -> totalhigh = 0; /*Does this supose to refer to HMA or reserved ram?*/
info -> freehigh = 0;
return 0;
}
//==============================================================================
void Logger::outputDebugString (const String& text)
{
std::cerr << text << std::endl;
}
//==============================================================================
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
{
return FreeBSD;
}
String SystemStats::getOperatingSystemName()
{
return "FreeBSD";
}
bool SystemStats::isOperatingSystem64Bit()
{
#if BEAST_64BIT
return true;
#else
//xxx not sure how to find this out?..
return false;
#endif
}
//==============================================================================
namespace BSDStatsHelpers
{
String getDmesgInfo (const char* const key)
{
StringArray lines;
File ("/var/run/dmesg.boot").readLines (lines);
for (int i = lines.size(); --i >= 0;) // (NB - it's important that this runs in reverse order)
if (lines[i].startsWith (key))
return lines[i].substring (strlen (key)).trim();
return String::empty;
}
}
String SystemStats::getCpuVendor()
{
return BSDStatsHelpers::getDmesgInfo (" Origin =").upToFirstOccurrenceOf (" ", false, false).unquoted();
}
int SystemStats::getCpuSpeedInMegaherz()
{
return roundToInt (BSDStatsHelpers::getDmesgInfo ("CPU:").fromLastOccurrenceOf ("(", false, false).upToFirstOccurrenceOf ("-MHz", false, false).getFloatValue());
}
int SystemStats::getMemorySizeInMegabytes()
{
struct sysinfo sysi;
if (sysinfo (&sysi) == 0)
return (sysi.totalram * sysi.mem_unit / (1024 * 1024));
return 0;
}
int SystemStats::getPageSize()
{
return sysconf (_SC_PAGESIZE);
}
//==============================================================================
String SystemStats::getLogonName()
{
const char* user = getenv ("USER");
if (user == nullptr)
{
struct passwd* const pw = getpwuid (getuid());
if (pw != nullptr)
user = pw->pw_name;
}
return CharPointer_UTF8 (user);
}
String SystemStats::getFullUserName()
{
return getLogonName();
}
String SystemStats::getComputerName()
{
char name [256] = { 0 };
if (gethostname (name, sizeof (name) - 1) == 0)
return name;
return String::empty;
}
String getLocaleValue (nl_item key)
{
const char* oldLocale = ::setlocale (LC_ALL, "");
return String (const_cast <const char*> (nl_langinfo (key)));
::setlocale (LC_ALL, oldLocale);
}
String SystemStats::getUserLanguage()
{
return "Uknown user language";
}
String SystemStats::getUserRegion()
{
return "Unknown user region";
}
String SystemStats::getDisplayLanguage()
{
return getUserLanguage();
}
//==============================================================================
void CPUInformation::initialise() noexcept
{
const String features (BSDStatsHelpers::getDmesgInfo (" Features="));
hasMMX = features.contains ("MMX");
hasSSE = features.contains ("SSE");
hasSSE2 = features.contains ("SSE2");
const String features2 (BSDStatsHelpers::getDmesgInfo (" Features2="));
hasSSE3 = features2.contains ("SSE3");
const String amdfeatures2 (BSDStatsHelpers::getDmesgInfo (" AMD Features2="));
has3DNow = amdfeatures2.contains ("3DNow!");
GETSYSCTL("hw.ncpu", numCpus);
if (numCpus == -1) numCpus = 1;
}
//==============================================================================
std::uint32_t beast_millisecondsSinceStartup() noexcept
{
timespec t;
clock_gettime (CLOCK_MONOTONIC, &t);
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
}
std::int64_t Time::getHighResolutionTicks() noexcept
{
timespec t;
clock_gettime (CLOCK_MONOTONIC, &t);
return (t.tv_sec * (std::int64_t) 1000000) + (t.tv_nsec / 1000);
}
std::int64_t Time::getHighResolutionTicksPerSecond() noexcept
{
return 1000000; // (microseconds)
}
double Time::getMillisecondCounterHiRes() noexcept
{
return getHighResolutionTicks() * 0.001;
}
bool Time::setSystemTimeToThisTime() const
{
timeval t;
t.tv_sec = millisSinceEpoch / 1000;
t.tv_usec = (millisSinceEpoch - t.tv_sec * 1000) * 1000;
return settimeofday (&t, 0) == 0;
}
} // beast

View File

@@ -0,0 +1,74 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
/*
Note that a lot of methods that you'd expect to find in this file actually
live in beast_posix_SharedCode.h!
*/
//==============================================================================
void Process::setPriority (const ProcessPriority prior)
{
const int policy = (prior <= NormalPriority) ? SCHED_OTHER : SCHED_RR;
const int minp = sched_get_priority_min (policy);
const int maxp = sched_get_priority_max (policy);
struct sched_param param;
switch (prior)
{
case LowPriority:
case NormalPriority: param.sched_priority = 0; break;
case HighPriority: param.sched_priority = minp + (maxp - minp) / 4; break;
case RealtimePriority: param.sched_priority = minp + (3 * (maxp - minp) / 4); break;
default: bassertfalse; break;
}
pthread_setschedparam (pthread_self(), policy, &param);
}
bool beast_isRunningUnderDebugger()
{
// XXX not implemented for FreeBSD!
// bassertfalse; // commented out since it calls isRunningUnderDebugger recursively
return false;
}
bool Process::isRunningUnderDebugger()
{
return beast_isRunningUnderDebugger();
}
static void swapUserAndEffectiveUser()
{
(void) setreuid (geteuid(), getuid());
(void) setregid (getegid(), getgid());
}
void Process::raisePrivilege() { if (geteuid() != 0 && getuid() == 0) swapUserAndEffectiveUser(); }
void Process::lowerPrivilege() { if (geteuid() == 0 && getuid() != 0) swapUserAndEffectiveUser(); }
} // beast

View File

@@ -0,0 +1,374 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
enum
{
U_ISOFS_SUPER_MAGIC = 0x9660, // linux/iso_fs.h
U_MSDOS_SUPER_MAGIC = 0x4d44, // linux/msdos_fs.h
U_NFS_SUPER_MAGIC = 0x6969, // linux/nfs_fs.h
U_SMB_SUPER_MAGIC = 0x517B // linux/smb_fs.h
};
//==============================================================================
bool File::copyInternal (const File& dest) const
{
FileInputStream in (*this);
if (dest.deleteFile())
{
{
FileOutputStream out (dest);
if (out.failedToOpen())
return false;
if (out.writeFromInputStream (in, -1) == getSize())
return true;
}
dest.deleteFile();
}
return false;
}
void File::findFileSystemRoots (Array<File>& destArray)
{
destArray.add (File ("/"));
}
//==============================================================================
bool File::isOnCDRomDrive() const
{
struct statfs buf;
return statfs (getFullPathName().toUTF8(), &buf) == 0
&& buf.f_type == (short) U_ISOFS_SUPER_MAGIC;
}
bool File::isOnHardDisk() const
{
struct statfs buf;
if (statfs (getFullPathName().toUTF8(), &buf) == 0)
{
switch (buf.f_type)
{
case U_ISOFS_SUPER_MAGIC: // CD-ROM
case U_MSDOS_SUPER_MAGIC: // Probably floppy (but could be mounted FAT filesystem)
case U_NFS_SUPER_MAGIC: // Network NFS
case U_SMB_SUPER_MAGIC: // Network Samba
return false;
default:
// Assume anything else is a hard-disk (but note it could
// be a RAM disk. There isn't a good way of determining
// this for sure)
return true;
}
}
// Assume so if this fails for some reason
return true;
}
bool File::isOnRemovableDrive() const
{
bassertfalse; // xxx not implemented for linux!
return false;
}
bool File::isHidden() const
{
return getFileName().startsWithChar ('.');
}
//==============================================================================
namespace
{
File beast_readlink (const String& file, const File& defaultFile)
{
const size_t size = 8192;
HeapBlock<char> buffer;
buffer.malloc (size + 4);
const size_t numBytes = readlink (file.toUTF8(), buffer, size);
if (numBytes > 0 && numBytes <= size)
return File (file).getSiblingFile (String::fromUTF8 (buffer, (int) numBytes));
return defaultFile;
}
}
File File::getLinkedTarget() const
{
return beast_readlink (getFullPathName().toUTF8(), *this);
}
//==============================================================================
static File resolveXDGFolder (const char* const type, const char* const fallbackFolder)
{
StringArray confLines;
File ("~/.config/user-dirs.dirs").readLines (confLines);
for (int i = 0; i < confLines.size(); ++i)
{
const String line (confLines[i].trimStart());
if (line.startsWith (type))
{
// eg. resolve XDG_MUSIC_DIR="$HOME/Music" to /home/user/Music
const File f (line.replace ("$HOME", File ("~").getFullPathName())
.fromFirstOccurrenceOf ("=", false, false)
.trim().unquoted());
if (f.isDirectory())
return f;
}
}
return File (fallbackFolder);
}
const char* const* beast_argv = nullptr;
int beast_argc = 0;
File File::getSpecialLocation (const SpecialLocationType type)
{
switch (type)
{
case userHomeDirectory:
{
const char* homeDir = getenv ("HOME");
if (const char* homeDir = getenv ("HOME"))
return File (CharPointer_UTF8 (homeDir));
if (struct passwd* const pw = getpwuid (getuid()))
return File (CharPointer_UTF8 (pw->pw_dir));
return File (CharPointer_UTF8 (homeDir));
}
case userDocumentsDirectory: return resolveXDGFolder ("XDG_DOCUMENTS_DIR", "~");
case userMusicDirectory: return resolveXDGFolder ("XDG_MUSIC_DIR", "~");
case userMoviesDirectory: return resolveXDGFolder ("XDG_VIDEOS_DIR", "~");
case userPicturesDirectory: return resolveXDGFolder ("XDG_PICTURES_DIR", "~");
case userDesktopDirectory: return resolveXDGFolder ("XDG_DESKTOP_DIR", "~/Desktop");
case userApplicationDataDirectory: return File ("~");
case commonDocumentsDirectory:
case commonApplicationDataDirectory: return File ("/var");
case globalApplicationsDirectory: return File ("/usr");
case tempDirectory:
{
File tmp ("/var/tmp");
if (! tmp.isDirectory())
{
tmp = "/tmp";
if (! tmp.isDirectory())
tmp = File::getCurrentWorkingDirectory();
}
return tmp;
}
case invokedExecutableFile:
if (beast_argv != nullptr && beast_argc > 0)
return File (CharPointer_UTF8 (beast_argv[0]));
// deliberate fall-through...
case currentExecutableFile:
case currentApplicationFile:
return beast_getExecutableFile();
case hostApplicationPath:
return beast_readlink ("/proc/self/exe", beast_getExecutableFile());
default:
bassertfalse; // unknown type?
break;
}
return File::nonexistent ();
}
//==============================================================================
String File::getVersion() const
{
return String::empty; // xxx not yet implemented
}
//==============================================================================
bool File::moveToTrash() const
{
if (! exists())
return true;
File trashCan ("~/.Trash");
if (! trashCan.isDirectory())
trashCan = "~/.local/share/Trash/files";
if (! trashCan.isDirectory())
return false;
return moveFileTo (trashCan.getNonexistentChildFile (getFileNameWithoutExtension(),
getFileExtension()));
}
//==============================================================================
class DirectoryIterator::NativeIterator::Pimpl : public Uncopyable
{
public:
Pimpl (const File& directory, const String& wildCard_)
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
wildCard (wildCard_),
dir (opendir (directory.getFullPathName().toUTF8()))
{
}
~Pimpl()
{
if (dir != nullptr)
closedir (dir);
}
bool next (String& filenameFound,
bool* const isDir, bool* const isHidden, std::int64_t* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
if (dir != nullptr)
{
const char* wildcardUTF8 = nullptr;
for (;;)
{
struct dirent* const de = readdir (dir);
if (de == nullptr)
break;
if (wildcardUTF8 == nullptr)
wildcardUTF8 = wildCard.toUTF8();
if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0)
{
filenameFound = CharPointer_UTF8 (de->d_name);
updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly);
if (isHidden != nullptr)
*isHidden = filenameFound.startsWithChar ('.');
return true;
}
}
}
return false;
}
private:
String parentDir, wildCard;
DIR* dir;
};
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
{
}
DirectoryIterator::NativeIterator::~NativeIterator()
{
}
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
bool* const isDir, bool* const isHidden, std::int64_t* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
}
//==============================================================================
static bool isFileExecutable (const String& filename)
{
beast_statStruct info;
return beast_stat (filename, info)
&& S_ISREG (info.st_mode)
&& access (filename.toUTF8(), X_OK) == 0;
}
bool Process::openDocument (const String& fileName, const String& parameters)
{
String cmdString (fileName.replace (" ", "\\ ",false));
cmdString << " " << parameters;
if ( cmdString.startsWithIgnoreCase ("file:")
|| File::createFileWithoutCheckingPath (fileName).isDirectory()
|| ! isFileExecutable (fileName))
{
// create a command that tries to launch a bunch of likely browsers
const char* const browserNames[] = { "xdg-open", "/etc/alternatives/x-www-browser", "firefox", "mozilla",
"google-chrome", "chromium-browser", "opera", "konqueror" };
StringArray cmdLines;
for (int i = 0; i < numElementsInArray (browserNames); ++i)
cmdLines.add (String (browserNames[i]) + " " + cmdString.trim().quoted());
cmdString = cmdLines.joinIntoString (" || ");
}
const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), 0 };
const int cpid = fork();
if (cpid == 0)
{
setsid();
// Child process
execve (argv[0], (char**) argv, environ);
exit (0);
}
return cpid >= 0;
}
void File::revealToUser() const
{
if (isDirectory())
startAsProcess();
else if (getParentDirectory().exists())
getParentDirectory().startAsProcess();
}
} // beast

View File

@@ -0,0 +1,181 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
void Logger::outputDebugString (const String& text)
{
std::cerr << text << std::endl;
}
//==============================================================================
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
{
return Linux;
}
String SystemStats::getOperatingSystemName()
{
return "Linux";
}
bool SystemStats::isOperatingSystem64Bit()
{
#if BEAST_64BIT
return true;
#else
//xxx not sure how to find this out?..
return false;
#endif
}
//==============================================================================
namespace LinuxStatsHelpers
{
String getCpuInfo (const char* const key)
{
StringArray lines;
File ("/proc/cpuinfo").readLines (lines);
for (int i = lines.size(); --i >= 0;) // (NB - it's important that this runs in reverse order)
if (lines[i].startsWithIgnoreCase (key))
return lines[i].fromFirstOccurrenceOf (":", false, false).trim();
return String::empty;
}
}
String SystemStats::getCpuVendor()
{
return LinuxStatsHelpers::getCpuInfo ("vendor_id");
}
int SystemStats::getCpuSpeedInMegaherz()
{
return roundToInt (LinuxStatsHelpers::getCpuInfo ("cpu MHz").getFloatValue());
}
int SystemStats::getMemorySizeInMegabytes()
{
struct sysinfo sysi;
if (sysinfo (&sysi) == 0)
return sysi.totalram * sysi.mem_unit / (1024 * 1024);
return 0;
}
int SystemStats::getPageSize()
{
return sysconf (_SC_PAGESIZE);
}
//==============================================================================
String SystemStats::getLogonName()
{
const char* user = getenv ("USER");
if (user == nullptr)
if (passwd* const pw = getpwuid (getuid()))
user = pw->pw_name;
return CharPointer_UTF8 (user);
}
String SystemStats::getFullUserName()
{
return getLogonName();
}
String SystemStats::getComputerName()
{
char name [256] = { 0 };
if (gethostname (name, sizeof (name) - 1) == 0)
return name;
return String::empty;
}
static String getLocaleValue (nl_item key)
{
const char* oldLocale = ::setlocale (LC_ALL, "");
String result (String::fromUTF8 (nl_langinfo (key)));
::setlocale (LC_ALL, oldLocale);
return result;
}
String SystemStats::getUserLanguage() { return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); }
String SystemStats::getUserRegion() { return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); }
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
//==============================================================================
void CPUInformation::initialise() noexcept
{
const String flags (LinuxStatsHelpers::getCpuInfo ("flags"));
hasMMX = flags.contains ("mmx");
hasSSE = flags.contains ("sse");
hasSSE2 = flags.contains ("sse2");
hasSSE3 = flags.contains ("sse3");
has3DNow = flags.contains ("3dnow");
numCpus = LinuxStatsHelpers::getCpuInfo ("processor").getIntValue() + 1;
}
//==============================================================================
std::uint32_t beast_millisecondsSinceStartup() noexcept
{
timespec t;
clock_gettime (CLOCK_MONOTONIC, &t);
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
}
std::int64_t Time::getHighResolutionTicks() noexcept
{
timespec t;
clock_gettime (CLOCK_MONOTONIC, &t);
return (t.tv_sec * (std::int64_t) 1000000) + (t.tv_nsec / 1000);
}
std::int64_t Time::getHighResolutionTicksPerSecond() noexcept
{
return 1000000; // (microseconds)
}
double Time::getMillisecondCounterHiRes() noexcept
{
return getHighResolutionTicks() * 0.001;
}
bool Time::setSystemTimeToThisTime() const
{
timeval t;
t.tv_sec = millisSinceEpoch / 1000;
t.tv_usec = (millisSinceEpoch - t.tv_sec * 1000) * 1000;
return settimeofday (&t, 0) == 0;
}
} // beast

View File

@@ -0,0 +1,89 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
/*
Note that a lot of methods that you'd expect to find in this file actually
live in beast_posix_SharedCode.h!
*/
//==============================================================================
void Process::setPriority (const ProcessPriority prior)
{
const int policy = (prior <= NormalPriority) ? SCHED_OTHER : SCHED_RR;
const int minp = sched_get_priority_min (policy);
const int maxp = sched_get_priority_max (policy);
struct sched_param param;
switch (prior)
{
case LowPriority:
case NormalPriority: param.sched_priority = 0; break;
case HighPriority: param.sched_priority = minp + (maxp - minp) / 4; break;
case RealtimePriority: param.sched_priority = minp + (3 * (maxp - minp) / 4); break;
default: bassertfalse; break;
}
pthread_setschedparam (pthread_self(), policy, &param);
}
bool beast_isRunningUnderDebugger()
{
static char testResult = 0;
if (testResult == 0)
{
testResult = (char) ptrace (PT_TRACE_ME, 0, 0, 0);
if (testResult >= 0)
{
ptrace (PT_DETACH, 0, (caddr_t) 1, 0);
testResult = 1;
}
}
return testResult < 0;
}
bool Process::isRunningUnderDebugger()
{
return beast_isRunningUnderDebugger();
}
// TODO(tom): raisePrivilege and lowerPrivilege don't seem to be called. If we
// start using them, we should deal with the return codes of setreuid() and
// setregid().
static bool swapUserAndEffectiveUser()
{
auto r1 = setreuid (geteuid(), getuid());
auto r2 = setregid (getegid(), getgid());
return !(r1 || r2);
}
void Process::raisePrivilege() { if (geteuid() != 0 && getuid() == 0) swapUserAndEffectiveUser(); }
void Process::lowerPrivilege() { if (geteuid() == 0 && getuid() != 0) swapUserAndEffectiveUser(); }
} // beast

View File

@@ -0,0 +1,484 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
/*
Note that a lot of methods that you'd expect to find in this file actually
live in beast_posix_SharedCode.h!
*/
//==============================================================================
bool File::copyInternal (const File& dest) const
{
BEAST_AUTORELEASEPOOL
{
NSFileManager* fm = [NSFileManager defaultManager];
return [fm fileExistsAtPath: beastStringToNS (fullPath)]
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
&& [fm copyItemAtPath: beastStringToNS (fullPath)
toPath: beastStringToNS (dest.getFullPathName())
error: nil];
#else
&& [fm copyPath: beastStringToNS (fullPath)
toPath: beastStringToNS (dest.getFullPathName())
handler: nil];
#endif
}
}
void File::findFileSystemRoots (Array<File>& destArray)
{
destArray.add (File ("/"));
}
//==============================================================================
namespace FileHelpers
{
static bool isFileOnDriveType (const File& f, const char* const* types)
{
struct statfs buf;
if (beast_doStatFS (f, buf))
{
const String type (buf.f_fstypename);
while (*types != 0)
if (type.equalsIgnoreCase (*types++))
return true;
}
return false;
}
static bool isHiddenFile (const String& path)
{
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
BEAST_AUTORELEASEPOOL
{
NSNumber* hidden = nil;
NSError* err = nil;
return [[NSURL fileURLWithPath: beastStringToNS (path)]
getResourceValue: &hidden forKey: NSURLIsHiddenKey error: &err]
&& [hidden boolValue];
}
#elif BEAST_IOS
return File (path).getFileName().startsWithChar ('.');
#else
FSRef ref;
LSItemInfoRecord info;
return FSPathMakeRefWithOptions ((const UInt8*) path.toRawUTF8(), kFSPathMakeRefDoNotFollowLeafSymlink, &ref, 0) == noErr
&& LSCopyItemInfoForRef (&ref, kLSRequestBasicFlagsOnly, &info) == noErr
&& (info.flags & kLSItemInfoIsInvisible) != 0;
#endif
}
#if BEAST_IOS
String getIOSSystemLocation (NSSearchPathDirectory type)
{
return nsStringToBeast ([NSSearchPathForDirectoriesInDomains (type, NSUserDomainMask, YES)
objectAtIndex: 0]);
}
#endif
static bool launchExecutable (const String& pathAndArguments)
{
const char* const argv[4] = { "/bin/sh", "-c", pathAndArguments.toUTF8(), 0 };
const int cpid = fork();
if (cpid == 0)
{
// Child process
if (execve (argv[0], (char**) argv, 0) < 0)
exit (0);
}
else
{
if (cpid < 0)
return false;
}
return true;
}
}
bool File::isOnCDRomDrive() const
{
const char* const cdTypes[] = { "cd9660", "cdfs", "cddafs", "udf", 0 };
return FileHelpers::isFileOnDriveType (*this, cdTypes);
}
bool File::isOnHardDisk() const
{
const char* const nonHDTypes[] = { "nfs", "smbfs", "ramfs", 0 };
return ! (isOnCDRomDrive() || FileHelpers::isFileOnDriveType (*this, nonHDTypes));
}
bool File::isOnRemovableDrive() const
{
#if BEAST_IOS
return false; // xxx is this possible?
#else
BEAST_AUTORELEASEPOOL
{
BOOL removable = false;
[[NSWorkspace sharedWorkspace]
getFileSystemInfoForPath: beastStringToNS (getFullPathName())
isRemovable: &removable
isWritable: nil
isUnmountable: nil
description: nil
type: nil];
return removable;
}
#endif
}
bool File::isHidden() const
{
return FileHelpers::isHiddenFile (getFullPathName());
}
//==============================================================================
const char* const* beast_argv = nullptr;
int beast_argc = 0;
File File::getSpecialLocation (const SpecialLocationType type)
{
BEAST_AUTORELEASEPOOL
{
String resultPath;
switch (type)
{
case userHomeDirectory: resultPath = nsStringToBeast (NSHomeDirectory()); break;
#if BEAST_IOS
case userDocumentsDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDocumentDirectory); break;
case userDesktopDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDesktopDirectory); break;
case tempDirectory:
{
File tmp (FileHelpers::getIOSSystemLocation (NSCachesDirectory));
tmp = tmp.getChildFile (beast_getExecutableFile().getFileNameWithoutExtension());
tmp.createDirectory();
return tmp.getFullPathName();
}
#else
case userDocumentsDirectory: resultPath = "~/Documents"; break;
case userDesktopDirectory: resultPath = "~/Desktop"; break;
case tempDirectory:
{
File tmp ("~/Library/Caches/" + beast_getExecutableFile().getFileNameWithoutExtension());
tmp.createDirectory();
return tmp.getFullPathName();
}
#endif
case userMusicDirectory: resultPath = "~/Music"; break;
case userMoviesDirectory: resultPath = "~/Movies"; break;
case userPicturesDirectory: resultPath = "~/Pictures"; break;
case userApplicationDataDirectory: resultPath = "~/Library"; break;
case commonApplicationDataDirectory: resultPath = "/Library"; break;
case commonDocumentsDirectory: resultPath = "/Users/Shared"; break;
case globalApplicationsDirectory: resultPath = "/Applications"; break;
case invokedExecutableFile:
if (beast_argv != nullptr && beast_argc > 0)
return File (CharPointer_UTF8 (beast_argv[0]));
// deliberate fall-through...
case currentExecutableFile:
return beast_getExecutableFile();
case currentApplicationFile:
{
const File exe (beast_getExecutableFile());
const File parent (exe.getParentDirectory());
#if BEAST_IOS
return parent;
#else
return parent.getFullPathName().endsWithIgnoreCase ("Contents/MacOS")
? parent.getParentDirectory().getParentDirectory()
: exe;
#endif
}
case hostApplicationPath:
{
unsigned int size = 8192;
HeapBlock<char> buffer;
buffer.calloc (size + 8);
_NSGetExecutablePath (buffer.getData(), &size);
return String::fromUTF8 (buffer, (int) size);
}
default:
bassertfalse; // unknown type?
break;
}
if (resultPath.isNotEmpty())
return File (resultPath.convertToPrecomposedUnicode());
}
return File::nonexistent ();
}
//==============================================================================
String File::getVersion() const
{
BEAST_AUTORELEASEPOOL
{
if (NSBundle* bundle = [NSBundle bundleWithPath: beastStringToNS (getFullPathName())])
if (NSDictionary* info = [bundle infoDictionary])
if (NSString* name = [info valueForKey: nsStringLiteral ("CFBundleShortVersionString")])
return nsStringToBeast (name);
}
return String::empty;
}
//==============================================================================
File File::getLinkedTarget() const
{
#if BEAST_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
NSString* dest = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath: beastStringToNS (getFullPathName()) error: nil];
#else
// (the cast here avoids a deprecation warning)
NSString* dest = [((id) [NSFileManager defaultManager]) pathContentOfSymbolicLinkAtPath: beastStringToNS (getFullPathName())];
#endif
if (dest != nil)
return File (nsStringToBeast (dest));
return *this;
}
//==============================================================================
bool File::moveToTrash() const
{
if (! exists())
return true;
#if BEAST_IOS
return deleteFile(); //xxx is there a trashcan on the iOS?
#else
BEAST_AUTORELEASEPOOL
{
NSString* p = beastStringToNS (getFullPathName());
return [[NSWorkspace sharedWorkspace]
performFileOperation: NSWorkspaceRecycleOperation
source: [p stringByDeletingLastPathComponent]
destination: nsEmptyString()
files: [NSArray arrayWithObject: [p lastPathComponent]]
tag: nil ];
}
#endif
}
//==============================================================================
class DirectoryIterator::NativeIterator::Pimpl : public Uncopyable
{
public:
Pimpl (const File& directory, const String& wildCard_)
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
wildCard (wildCard_),
enumerator (nil)
{
BEAST_AUTORELEASEPOOL
{
enumerator = [[[NSFileManager defaultManager] enumeratorAtPath: beastStringToNS (directory.getFullPathName())] retain];
}
}
~Pimpl()
{
[enumerator release];
}
bool next (String& filenameFound,
bool* const isDir, bool* const isHidden, std::int64_t* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
BEAST_AUTORELEASEPOOL
{
const char* wildcardUTF8 = nullptr;
for (;;)
{
NSString* file;
if (enumerator == nil || (file = [enumerator nextObject]) == nil)
return false;
[enumerator skipDescendents];
filenameFound = nsStringToBeast (file);
if (wildcardUTF8 == nullptr)
wildcardUTF8 = wildCard.toUTF8();
if (fnmatch (wildcardUTF8, filenameFound.toUTF8(), FNM_CASEFOLD) != 0)
continue;
const String fullPath (parentDir + filenameFound);
updateStatInfoForFile (fullPath, isDir, fileSize, modTime, creationTime, isReadOnly);
if (isHidden != nullptr)
*isHidden = FileHelpers::isHiddenFile (fullPath);
return true;
}
}
}
private:
String parentDir, wildCard;
NSDirectoryEnumerator* enumerator;
};
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildcard)
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildcard))
{
}
DirectoryIterator::NativeIterator::~NativeIterator()
{
}
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
bool* const isDir, bool* const isHidden, std::int64_t* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
}
//==============================================================================
bool Process::openDocument (const String& fileName, const String& parameters)
{
#if BEAST_IOS
return [[UIApplication sharedApplication] openURL: [NSURL URLWithString: beastStringToNS (fileName)]];
#else
BEAST_AUTORELEASEPOOL
{
if (parameters.isEmpty())
{
return [[NSWorkspace sharedWorkspace] openFile: beastStringToNS (fileName)]
|| [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: beastStringToNS (fileName)]];
}
bool ok = false;
const File file (fileName);
if (file.isBundle())
{
NSMutableArray* urls = [NSMutableArray array];
StringArray docs;
docs.addTokens (parameters, true);
for (int i = 0; i < docs.size(); ++i)
[urls addObject: beastStringToNS (docs[i])];
ok = [[NSWorkspace sharedWorkspace] openURLs: urls
withAppBundleIdentifier: [[NSBundle bundleWithPath: beastStringToNS (fileName)] bundleIdentifier]
options: 0
additionalEventParamDescriptor: nil
launchIdentifiers: nil];
}
else if (file.exists())
{
ok = FileHelpers::launchExecutable ("\"" + fileName + "\" " + parameters);
}
return ok;
}
#endif
}
void File::revealToUser() const
{
#if ! BEAST_IOS
if (exists())
[[NSWorkspace sharedWorkspace] selectFile: beastStringToNS (getFullPathName()) inFileViewerRootedAtPath: nsEmptyString()];
else if (getParentDirectory().exists())
getParentDirectory().revealToUser();
#endif
}
//==============================================================================
OSType File::getMacOSType() const
{
BEAST_AUTORELEASEPOOL
{
#if BEAST_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
NSDictionary* fileDict = [[NSFileManager defaultManager] attributesOfItemAtPath: beastStringToNS (getFullPathName()) error: nil];
#else
// (the cast here avoids a deprecation warning)
NSDictionary* fileDict = [((id) [NSFileManager defaultManager]) fileAttributesAtPath: beastStringToNS (getFullPathName()) traverseLink: NO];
#endif
return [fileDict fileHFSTypeCode];
}
}
bool File::isBundle() const
{
#if BEAST_IOS
return false; // xxx can't find a sensible way to do this without trying to open the bundle..
#else
BEAST_AUTORELEASEPOOL
{
return [[NSWorkspace sharedWorkspace] isFilePackageAtPath: beastStringToNS (getFullPathName())];
}
#endif
}
#if BEAST_MAC
void File::addToDock() const
{
// check that it's not already there...
if (! beast_getOutputFromCommand ("defaults read com.apple.dock persistent-apps").containsIgnoreCase (getFullPathName()))
{
beast_runSystemCommand ("defaults write com.apple.dock persistent-apps -array-add \"<dict><key>tile-data</key><dict><key>file-data</key><dict><key>_CFURLString</key><string>"
+ getFullPathName() + "</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>\"");
beast_runSystemCommand ("osascript -e \"tell application \\\"Dock\\\" to quit\"");
}
}
#endif
} // beast

View File

@@ -0,0 +1,96 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
String String::fromCFString (CFStringRef cfString)
{
if (cfString == 0)
return String::empty;
CFRange range = { 0, CFStringGetLength (cfString) };
HeapBlock <UniChar> u ((size_t) range.length + 1);
CFStringGetCharacters (cfString, range, u);
u[range.length] = 0;
return String (CharPointer_UTF16 ((const CharPointer_UTF16::CharType*) u.getData()));
}
CFStringRef String::toCFString() const
{
CharPointer_UTF16 utf16 (toUTF16());
return CFStringCreateWithCharacters (kCFAllocatorDefault, (const UniChar*) utf16.getAddress(), (CFIndex) utf16.length());
}
String String::convertToPrecomposedUnicode() const
{
#if BEAST_IOS
BEAST_AUTORELEASEPOOL
{
return nsStringToBeast ([beastStringToNS (*this) precomposedStringWithCanonicalMapping]);
}
#else
UnicodeMapping map;
map.unicodeEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
kUnicodeNoSubset,
kTextEncodingDefaultFormat);
map.otherEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
kUnicodeCanonicalCompVariant,
kTextEncodingDefaultFormat);
map.mappingVersion = kUnicodeUseLatestMapping;
UnicodeToTextInfo conversionInfo = 0;
String result;
if (CreateUnicodeToTextInfo (&map, &conversionInfo) == noErr)
{
const size_t bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (getCharPointer());
HeapBlock <char> tempOut;
tempOut.calloc (bytesNeeded + 4);
ByteCount bytesRead = 0;
ByteCount outputBufferSize = 0;
if (ConvertFromUnicodeToText (conversionInfo,
bytesNeeded, (ConstUniCharArrayPtr) toUTF16().getAddress(),
kUnicodeDefaultDirectionMask,
0, 0, 0, 0,
bytesNeeded, &bytesRead,
&outputBufferSize, tempOut) == noErr)
{
result = String (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) tempOut.getData()));
}
DisposeUnicodeToTextInfo (&conversionInfo);
}
return result;
#endif
}
} // beast

View File

@@ -0,0 +1,296 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
ScopedAutoReleasePool::ScopedAutoReleasePool()
{
pool = [[NSAutoreleasePool alloc] init];
}
ScopedAutoReleasePool::~ScopedAutoReleasePool()
{
[((NSAutoreleasePool*) pool) release];
}
//==============================================================================
void Logger::outputDebugString (const String& text)
{
// Would prefer to use std::cerr here, but avoiding it for
// the moment, due to clang JIT linkage problems.
fputs (text.toRawUTF8(), stderr);
fputs ("\n", stderr);
fflush (stderr);
}
//==============================================================================
namespace SystemStatsHelpers
{
#if BEAST_INTEL && ! BEAST_NO_INLINE_ASM
static void doCPUID (std::uint32_t& a, std::uint32_t& b, std::uint32_t& c, std::uint32_t& d, std::uint32_t type)
{
std::uint32_t la = a, lb = b, lc = c, ld = d;
asm ("mov %%ebx, %%esi \n\t"
"cpuid \n\t"
"xchg %%esi, %%ebx"
: "=a" (la), "=S" (lb), "=c" (lc), "=d" (ld) : "a" (type)
#if BEAST_64BIT
, "b" (lb), "c" (lc), "d" (ld)
#endif
);
a = la; b = lb; c = lc; d = ld;
}
#endif
}
//==============================================================================
void CPUInformation::initialise() noexcept
{
#if BEAST_INTEL && ! BEAST_NO_INLINE_ASM
std::uint32_t a = 0, b = 0, d = 0, c = 0;
SystemStatsHelpers::doCPUID (a, b, c, d, 1);
hasMMX = (d & (1u << 23)) != 0;
hasSSE = (d & (1u << 25)) != 0;
hasSSE2 = (d & (1u << 26)) != 0;
has3DNow = (b & (1u << 31)) != 0;
hasSSE3 = (c & (1u << 0)) != 0;
#endif
#if BEAST_IOS || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
numCpus = (int) [[NSProcessInfo processInfo] activeProcessorCount];
#else
numCpus = (int) MPProcessors();
#endif
}
#if BEAST_MAC
struct RLimitInitialiser
{
RLimitInitialiser()
{
rlimit lim;
getrlimit (RLIMIT_NOFILE, &lim);
lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
setrlimit (RLIMIT_NOFILE, &lim);
}
};
static RLimitInitialiser rLimitInitialiser;
#endif
//==============================================================================
#if ! BEAST_IOS
static String getOSXVersion()
{
BEAST_AUTORELEASEPOOL
{
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile:
nsStringLiteral ("/System/Library/CoreServices/SystemVersion.plist")];
return nsStringToBeast ([dict objectForKey: nsStringLiteral ("ProductVersion")]);
}
}
#endif
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
{
#if BEAST_IOS
return iOS;
#else
StringArray parts;
parts.addTokens (getOSXVersion(), ".", String::empty);
bassert (parts[0].getIntValue() == 10);
const int major = parts[1].getIntValue();
bassert (major > 2);
return (OperatingSystemType) (major + MacOSX_10_4 - 4);
#endif
}
String SystemStats::getOperatingSystemName()
{
#if BEAST_IOS
return "iOS " + nsStringToBeast ([[UIDevice currentDevice] systemVersion]);
#else
return "Mac OSX " + getOSXVersion();
#endif
}
bool SystemStats::isOperatingSystem64Bit()
{
#if BEAST_IOS
return false;
#elif BEAST_64BIT
return true;
#else
return getOperatingSystemType() >= MacOSX_10_6;
#endif
}
int SystemStats::getMemorySizeInMegabytes()
{
std::uint64_t mem = 0;
size_t memSize = sizeof (mem);
int mib[] = { CTL_HW, HW_MEMSIZE };
sysctl (mib, 2, &mem, &memSize, 0, 0);
return (int) (mem / (1024 * 1024));
}
String SystemStats::getCpuVendor()
{
#if BEAST_INTEL && ! BEAST_NO_INLINE_ASM
std::uint32_t dummy = 0;
std::uint32_t vendor[4] = { 0 };
SystemStatsHelpers::doCPUID (dummy, vendor[0], vendor[2], vendor[1], 0);
return String (reinterpret_cast <const char*> (vendor), 12);
#else
return String::empty;
#endif
}
int SystemStats::getCpuSpeedInMegaherz()
{
std::uint64_t speedHz = 0;
size_t speedSize = sizeof (speedHz);
int mib[] = { CTL_HW, HW_CPU_FREQ };
sysctl (mib, 2, &speedHz, &speedSize, 0, 0);
#if BEAST_BIG_ENDIAN
if (speedSize == 4)
speedHz >>= 32;
#endif
return (int) (speedHz / 1000000);
}
//==============================================================================
String SystemStats::getLogonName()
{
return nsStringToBeast (NSUserName());
}
String SystemStats::getFullUserName()
{
return nsStringToBeast (NSFullUserName());
}
String SystemStats::getComputerName()
{
char name [256] = { 0 };
if (gethostname (name, sizeof (name) - 1) == 0)
return String (name).upToLastOccurrenceOf (".local", false, true);
return String::empty;
}
static String getLocaleValue (CFStringRef key)
{
CFLocaleRef cfLocale = CFLocaleCopyCurrent();
const String result (String::fromCFString ((CFStringRef) CFLocaleGetValue (cfLocale, key)));
CFRelease (cfLocale);
return result;
}
String SystemStats::getUserLanguage() { return getLocaleValue (kCFLocaleLanguageCode); }
String SystemStats::getUserRegion() { return getLocaleValue (kCFLocaleCountryCode); }
String SystemStats::getDisplayLanguage()
{
CFArrayRef cfPrefLangs = CFLocaleCopyPreferredLanguages();
const String result (String::fromCFString ((CFStringRef) CFArrayGetValueAtIndex (cfPrefLangs, 0)));
CFRelease (cfPrefLangs);
return result;
}
//==============================================================================
class HiResCounterHandler
{
public:
HiResCounterHandler()
{
mach_timebase_info_data_t timebase;
(void) mach_timebase_info (&timebase);
if (timebase.numer % 1000000 == 0)
{
numerator = timebase.numer / 1000000;
denominator = timebase.denom;
}
else
{
numerator = timebase.numer;
denominator = timebase.denom * (std::uint64_t) 1000000;
}
highResTimerFrequency = (timebase.denom * (std::uint64_t) 1000000000) / timebase.numer;
highResTimerToMillisecRatio = numerator / (double) denominator;
}
inline std::uint32_t millisecondsSinceStartup() const noexcept
{
return (std::uint32_t) ((mach_absolute_time() * numerator) / denominator);
}
inline double getMillisecondCounterHiRes() const noexcept
{
return mach_absolute_time() * highResTimerToMillisecRatio;
}
std::int64_t highResTimerFrequency;
private:
std::uint64_t numerator, denominator;
double highResTimerToMillisecRatio;
};
static HiResCounterHandler& hiResCounterHandler()
{
static HiResCounterHandler hiResCounterHandler;
return hiResCounterHandler;
}
std::uint32_t beast_millisecondsSinceStartup() noexcept { return hiResCounterHandler().millisecondsSinceStartup(); }
double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterHandler().getMillisecondCounterHiRes(); }
std::int64_t Time::getHighResolutionTicksPerSecond() noexcept { return hiResCounterHandler().highResTimerFrequency; }
std::int64_t Time::getHighResolutionTicks() noexcept { return (std::int64_t) mach_absolute_time(); }
bool Time::setSystemTimeToThisTime() const
{
bassertfalse;
return false;
}
//==============================================================================
int SystemStats::getPageSize()
{
return (int) NSPageSize();
}
} // beast

View File

@@ -0,0 +1,86 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
/*
Note that a lot of methods that you'd expect to find in this file actually
live in beast_posix_SharedCode.h!
*/
//==============================================================================
bool Process::isForegroundProcess()
{
#if BEAST_MAC
return [NSApp isActive];
#else
return true; // xxx change this if more than one app is ever possible on iOS!
#endif
}
void Process::makeForegroundProcess()
{
#if BEAST_MAC
[NSApp activateIgnoringOtherApps: YES];
#endif
}
void Process::raisePrivilege()
{
bassertfalse;
}
void Process::lowerPrivilege()
{
bassertfalse;
}
void Process::setPriority (ProcessPriority)
{
// xxx
}
//==============================================================================
bool beast_isRunningUnderDebugger()
{
static char testResult = 0;
if (testResult == 0)
{
struct kinfo_proc info;
int m[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
size_t sz = sizeof (info);
sysctl (m, 4, &info, &sz, 0, 0);
testResult = ((info.kp_proc.p_flag & P_TRACED) != 0) ? 1 : -1;
}
return testResult > 0;
}
bool Process::isRunningUnderDebugger()
{
return beast_isRunningUnderDebugger();
}
} // beast

View File

@@ -0,0 +1,154 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_OSX_OBJCHELPERS_H_INCLUDED
#define BEAST_OSX_OBJCHELPERS_H_INCLUDED
namespace beast
{
/* This file contains a few helper functions that are used internally but which
need to be kept away from the public headers because they use obj-C symbols.
*/
namespace
{
//==============================================================================
static inline String nsStringToBeast (NSString* s)
{
return CharPointer_UTF8 ([s UTF8String]);
}
static inline NSString* beastStringToNS (const String& s)
{
return [NSString stringWithUTF8String: s.toUTF8()];
}
static inline NSString* nsStringLiteral (const char* const s) noexcept
{
return [NSString stringWithUTF8String: s];
}
static inline NSString* nsEmptyString() noexcept
{
return [NSString string];
}
}
//==============================================================================
template <typename ObjectType>
struct NSObjectRetainer
{
inline NSObjectRetainer (ObjectType* o) : object (o) { [object retain]; }
inline ~NSObjectRetainer() { [object release]; }
ObjectType* object;
};
//==============================================================================
template <typename SuperclassType>
struct ObjCClass : public Uncopyable
{
ObjCClass (const char* nameRoot)
: cls (objc_allocateClassPair ([SuperclassType class], getRandomisedName (nameRoot).toUTF8(), 0))
{
}
~ObjCClass()
{
objc_disposeClassPair (cls);
}
void registerClass()
{
objc_registerClassPair (cls);
}
SuperclassType* createInstance() const
{
return class_createInstance (cls, 0);
}
template <typename Type>
void addIvar (const char* name)
{
BOOL b = class_addIvar (cls, name, sizeof (Type), (uint8_t) rint (log2 (sizeof (Type))), @encode (Type));
bassert (b); (void) b;
}
template <typename FunctionType>
void addMethod (SEL selector, FunctionType callbackFn, const char* signature)
{
BOOL b = class_addMethod (cls, selector, (IMP) callbackFn, signature);
bassert (b); (void) b;
}
template <typename FunctionType>
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2)
{
addMethod (selector, callbackFn, (String (sig1) + sig2).toUTF8());
}
template <typename FunctionType>
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2, const char* sig3)
{
addMethod (selector, callbackFn, (String (sig1) + sig2 + sig3).toUTF8());
}
template <typename FunctionType>
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2, const char* sig3, const char* sig4)
{
addMethod (selector, callbackFn, (String (sig1) + sig2 + sig3 + sig4).toUTF8());
}
void addProtocol (Protocol* protocol)
{
BOOL b = class_addProtocol (cls, protocol);
bassert (b); (void) b;
}
static id sendSuperclassMessage (id self, SEL selector)
{
objc_super s = { self, [SuperclassType class] };
return objc_msgSendSuper (&s, selector);
}
template <typename Type>
static Type getIvar (id self, const char* name)
{
void* v = nullptr;
object_getInstanceVariable (self, name, &v);
return static_cast <Type> (v);
}
Class cls;
private:
static String getRandomisedName (const char* root)
{
return root + String::toHexString (beast::Random::getSystemRandom().nextInt64());
}
};
} // beast
#endif // BEAST_OSX_OBJCHELPERS_H_INCLUDED

View File

@@ -0,0 +1,749 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
CriticalSection::CriticalSection() noexcept
{
pthread_mutexattr_t atts;
pthread_mutexattr_init (&atts);
pthread_mutexattr_settype (&atts, PTHREAD_MUTEX_RECURSIVE);
#if ! BEAST_ANDROID
pthread_mutexattr_setprotocol (&atts, PTHREAD_PRIO_INHERIT);
#endif
pthread_mutex_init (&mutex, &atts);
pthread_mutexattr_destroy (&atts);
}
CriticalSection::~CriticalSection() noexcept { pthread_mutex_destroy (&mutex); }
void CriticalSection::enter() const noexcept { pthread_mutex_lock (&mutex); }
bool CriticalSection::tryEnter() const noexcept { return pthread_mutex_trylock (&mutex) == 0; }
void CriticalSection::exit() const noexcept { pthread_mutex_unlock (&mutex); }
//==============================================================================
void Process::terminate()
{
#if BEAST_ANDROID || BEAST_BSD
// http://www.unix.com/man-page/FreeBSD/2/_exit/
::_exit (EXIT_FAILURE);
#else
std::_Exit (EXIT_FAILURE);
#endif
}
//==============================================================================
const beast_wchar File::separator = '/';
const String File::separatorString ("/");
//==============================================================================
File File::getCurrentWorkingDirectory()
{
HeapBlock<char> heapBuffer;
char localBuffer [1024];
char* cwd = getcwd (localBuffer, sizeof (localBuffer) - 1);
size_t bufferSize = 4096;
while (cwd == nullptr && errno == ERANGE)
{
heapBuffer.malloc (bufferSize);
cwd = getcwd (heapBuffer, bufferSize - 1);
bufferSize += 1024;
}
return File (CharPointer_UTF8 (cwd));
}
bool File::setAsCurrentWorkingDirectory() const
{
return chdir (getFullPathName().toUTF8()) == 0;
}
//==============================================================================
// The unix siginterrupt function is deprecated - this does the same job.
int beast_siginterrupt (int sig, int flag)
{
struct ::sigaction act;
(void) ::sigaction (sig, nullptr, &act);
if (flag != 0)
act.sa_flags &= ~SA_RESTART;
else
act.sa_flags |= SA_RESTART;
return ::sigaction (sig, &act, nullptr);
}
//==============================================================================
namespace
{
#if BEAST_LINUX || \
(BEAST_IOS && ! __DARWIN_ONLY_64_BIT_INO_T) // (this iOS stuff is to avoid a simulator bug)
typedef struct stat64 beast_statStruct;
#define BEAST_STAT stat64
#else
typedef struct stat beast_statStruct;
#define BEAST_STAT stat
#endif
bool beast_stat (const String& fileName, beast_statStruct& info)
{
return fileName.isNotEmpty()
&& BEAST_STAT (fileName.toUTF8(), &info) == 0;
}
// if this file doesn't exist, find a parent of it that does..
bool beast_doStatFS (File f, struct statfs& result)
{
for (int i = 5; --i >= 0;)
{
if (f.exists())
break;
f = f.getParentDirectory();
}
return statfs (f.getFullPathName().toUTF8(), &result) == 0;
}
void updateStatInfoForFile (const String& path, bool* const isDir, std::int64_t* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
if (isDir != nullptr || fileSize != nullptr || modTime != nullptr || creationTime != nullptr)
{
beast_statStruct info;
const bool statOk = beast_stat (path, info);
if (isDir != nullptr) *isDir = statOk && ((info.st_mode & S_IFDIR) != 0);
if (fileSize != nullptr) *fileSize = statOk ? info.st_size : 0;
if (modTime != nullptr) *modTime = Time (statOk ? (std::int64_t) info.st_mtime * 1000 : 0);
if (creationTime != nullptr) *creationTime = Time (statOk ? (std::int64_t) info.st_ctime * 1000 : 0);
}
if (isReadOnly != nullptr)
*isReadOnly = access (path.toUTF8(), W_OK) != 0;
}
Result getResultForErrno()
{
return Result::fail (String (strerror (errno)));
}
Result getResultForReturnValue (int value)
{
return value == -1 ? getResultForErrno() : Result::ok();
}
int getFD (void* handle) noexcept { return (int) (std::intptr_t) handle; }
void* fdToVoidPointer (int fd) noexcept { return (void*) (std::intptr_t) fd; }
}
bool File::isDirectory() const
{
beast_statStruct info;
return fullPath.isEmpty()
|| (beast_stat (fullPath, info) && ((info.st_mode & S_IFDIR) != 0));
}
bool File::exists() const
{
return fullPath.isNotEmpty()
&& access (fullPath.toUTF8(), F_OK) == 0;
}
bool File::existsAsFile() const
{
return exists() && ! isDirectory();
}
std::int64_t File::getSize() const
{
beast_statStruct info;
return beast_stat (fullPath, info) ? info.st_size : 0;
}
//==============================================================================
bool File::hasWriteAccess() const
{
if (exists())
return access (fullPath.toUTF8(), W_OK) == 0;
if ((! isDirectory()) && fullPath.containsChar (separator))
return getParentDirectory().hasWriteAccess();
return false;
}
bool File::setFileReadOnlyInternal (const bool shouldBeReadOnly) const
{
beast_statStruct info;
if (! beast_stat (fullPath, info))
return false;
info.st_mode &= 0777; // Just permissions
if (shouldBeReadOnly)
info.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
else
// Give everybody write permission?
info.st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
return chmod (fullPath.toUTF8(), info.st_mode) == 0;
}
void File::getFileTimesInternal (std::int64_t& modificationTime, std::int64_t& accessTime, std::int64_t& creationTime) const
{
modificationTime = 0;
accessTime = 0;
creationTime = 0;
beast_statStruct info;
if (beast_stat (fullPath, info))
{
modificationTime = (std::int64_t) info.st_mtime * 1000;
accessTime = (std::int64_t) info.st_atime * 1000;
creationTime = (std::int64_t) info.st_ctime * 1000;
}
}
bool File::setFileTimesInternal (std::int64_t modificationTime, std::int64_t accessTime, std::int64_t /*creationTime*/) const
{
beast_statStruct info;
if ((modificationTime != 0 || accessTime != 0) && beast_stat (fullPath, info))
{
struct utimbuf times;
times.actime = accessTime != 0 ? (time_t) (accessTime / 1000) : info.st_atime;
times.modtime = modificationTime != 0 ? (time_t) (modificationTime / 1000) : info.st_mtime;
return utime (fullPath.toUTF8(), &times) == 0;
}
return false;
}
bool File::deleteFile() const
{
if (! exists())
return true;
if (isDirectory())
return rmdir (fullPath.toUTF8()) == 0;
return remove (fullPath.toUTF8()) == 0;
}
bool File::moveInternal (const File& dest) const
{
if (rename (fullPath.toUTF8(), dest.getFullPathName().toUTF8()) == 0)
return true;
if (hasWriteAccess() && copyInternal (dest))
{
if (deleteFile())
return true;
dest.deleteFile();
}
return false;
}
Result File::createDirectoryInternal (const String& fileName) const
{
return getResultForReturnValue (mkdir (fileName.toUTF8(), 0777));
}
//=====================================================================
std::int64_t beast_fileSetPosition (void* handle, std::int64_t pos)
{
if (handle != 0 && lseek (getFD (handle), pos, SEEK_SET) == pos)
return pos;
return -1;
}
void FileInputStream::openHandle()
{
const int f = open (file.getFullPathName().toUTF8(), O_RDONLY, 00644);
if (f != -1)
fileHandle = fdToVoidPointer (f);
else
status = getResultForErrno();
}
void FileInputStream::closeHandle()
{
if (fileHandle != 0)
{
close (getFD (fileHandle));
fileHandle = 0;
}
}
size_t FileInputStream::readInternal (void* const buffer, const size_t numBytes)
{
std::ptrdiff_t result = 0;
if (fileHandle != 0)
{
result = ::read (getFD (fileHandle), buffer, numBytes);
if (result < 0)
{
status = getResultForErrno();
result = 0;
}
}
return (size_t) result;
}
//==============================================================================
void FileOutputStream::openHandle()
{
if (file.exists())
{
const int f = open (file.getFullPathName().toUTF8(), O_RDWR, 00644);
if (f != -1)
{
currentPosition = lseek (f, 0, SEEK_END);
if (currentPosition >= 0)
{
fileHandle = fdToVoidPointer (f);
}
else
{
status = getResultForErrno();
close (f);
}
}
else
{
status = getResultForErrno();
}
}
else
{
const int f = open (file.getFullPathName().toUTF8(), O_RDWR + O_CREAT, 00644);
if (f != -1)
fileHandle = fdToVoidPointer (f);
else
status = getResultForErrno();
}
}
void FileOutputStream::closeHandle()
{
if (fileHandle != 0)
{
close (getFD (fileHandle));
fileHandle = 0;
}
}
std::ptrdiff_t FileOutputStream::writeInternal (const void* const data, const size_t numBytes)
{
std::ptrdiff_t result = 0;
if (fileHandle != 0)
{
result = ::write (getFD (fileHandle), data, numBytes);
if (result == -1)
status = getResultForErrno();
}
return result;
}
void FileOutputStream::flushInternal()
{
if (fileHandle != 0)
{
if (fsync (getFD (fileHandle)) == -1)
status = getResultForErrno();
#if BEAST_ANDROID
// This stuff tells the OS to asynchronously update the metadata
// that the OS has cached aboud the file - this metadata is used
// when the device is acting as a USB drive, and unless it's explicitly
// refreshed, it'll get out of step with the real file.
const LocalRef<jstring> t (javaString (file.getFullPathName()));
android.activity.callVoidMethod (BeastAppActivity.scanFile, t.get());
#endif
}
}
Result FileOutputStream::truncate()
{
if (fileHandle == 0)
return status;
flush();
return getResultForReturnValue (ftruncate (getFD (fileHandle), (off_t) currentPosition));
}
//==============================================================================
Result RandomAccessFile::nativeOpen (File const& path, Mode mode)
{
bassert (! isOpen ());
Result result (Result::ok ());
if (path.exists())
{
int oflag;
switch (mode)
{
case readOnly:
oflag = O_RDONLY;
break;
default:
case readWrite:
oflag = O_RDWR;
break;
};
const int f = ::open (path.getFullPathName().toUTF8(), oflag, 00644);
if (f != -1)
{
currentPosition = lseek (f, 0, SEEK_SET);
if (currentPosition >= 0)
{
file = path;
fileHandle = fdToVoidPointer (f);
}
else
{
result = getResultForErrno();
::close (f);
}
}
else
{
result = getResultForErrno();
}
}
else if (mode == readWrite)
{
const int f = ::open (path.getFullPathName().toUTF8(), O_RDWR + O_CREAT, 00644);
if (f != -1)
{
file = path;
fileHandle = fdToVoidPointer (f);
}
else
{
result = getResultForErrno();
}
}
else
{
// file doesn't exist and we're opening read-only
Result::fail (String (strerror (ENOENT)));
}
return result;
}
void RandomAccessFile::nativeClose ()
{
bassert (isOpen ());
file = File::nonexistent ();
::close (getFD (fileHandle));
fileHandle = nullptr;
currentPosition = 0;
}
Result RandomAccessFile::nativeSetPosition (FileOffset newPosition)
{
bassert (isOpen ());
off_t const actualPosition = lseek (getFD (fileHandle), newPosition, SEEK_SET);
currentPosition = actualPosition;
if (actualPosition != newPosition)
{
// VFALCO NOTE I dislike return from the middle but
// Result::ok() is showing up in the profile
//
return getResultForErrno();
}
return Result::ok();
}
Result RandomAccessFile::nativeRead (void* buffer, ByteCount numBytes, ByteCount* pActualAmount)
{
bassert (isOpen ());
std::ptrdiff_t bytesRead = ::read (getFD (fileHandle), buffer, numBytes);
if (bytesRead < 0)
{
if (pActualAmount != nullptr)
*pActualAmount = 0;
// VFALCO NOTE I dislike return from the middle but
// Result::ok() is showing up in the profile
//
return getResultForErrno();
}
currentPosition += bytesRead;
if (pActualAmount != nullptr)
*pActualAmount = bytesRead;
return Result::ok();
}
Result RandomAccessFile::nativeWrite (void const* data, ByteCount numBytes, size_t* pActualAmount)
{
bassert (isOpen ());
std::ptrdiff_t bytesWritten = ::write (getFD (fileHandle), data, numBytes);
// write(3) says that the actual return will be exactly -1 on
// error, but we will assume anything negative indicates failure.
//
if (bytesWritten < 0)
{
if (pActualAmount != nullptr)
*pActualAmount = 0;
// VFALCO NOTE I dislike return from the middle but
// Result::ok() is showing up in the profile
//
return getResultForErrno();
}
if (pActualAmount != nullptr)
*pActualAmount = bytesWritten;
return Result::ok();
}
Result RandomAccessFile::nativeTruncate ()
{
bassert (isOpen ());
flush();
return getResultForReturnValue (ftruncate (getFD (fileHandle), (off_t) currentPosition));
}
Result RandomAccessFile::nativeFlush ()
{
bassert (isOpen ());
Result result (Result::ok ());
if (fsync (getFD (fileHandle)) == -1)
result = getResultForErrno();
#if BEAST_ANDROID
// This stuff tells the OS to asynchronously update the metadata
// that the OS has cached aboud the file - this metadata is used
// when the device is acting as a USB drive, and unless it's explicitly
// refreshed, it'll get out of step with the real file.
const LocalRef<jstring> t (javaString (file.getFullPathName()));
android.activity.callVoidMethod (BeastAppActivity.scanFile, t.get());
#endif
return result;
}
//==============================================================================
String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue)
{
if (const char* s = ::getenv (name.toUTF8()))
return String::fromUTF8 (s);
return defaultValue;
}
//==============================================================================
#if BEAST_PROBEASTR_LIVE_BUILD
extern "C" const char* beast_getCurrentExecutablePath();
#endif
File beast_getExecutableFile();
File beast_getExecutableFile()
{
#if BEAST_PROBEASTR_LIVE_BUILD
return File (beast_getCurrentExecutablePath());
#elif BEAST_ANDROID
return File (android.appFile);
#else
struct DLAddrReader
{
static String getFilename()
{
Dl_info exeInfo;
dladdr ((void*) beast_getExecutableFile, &exeInfo);
return CharPointer_UTF8 (exeInfo.dli_fname);
}
};
static String filename (DLAddrReader::getFilename());
return File::getCurrentWorkingDirectory().getChildFile (filename);
#endif
}
//==============================================================================
std::int64_t File::getBytesFreeOnVolume() const
{
struct statfs buf;
if (beast_doStatFS (*this, buf))
return (std::int64_t) buf.f_bsize * (std::int64_t) buf.f_bavail; // Note: this returns space available to non-super user
return 0;
}
std::int64_t File::getVolumeTotalSize() const
{
struct statfs buf;
if (beast_doStatFS (*this, buf))
return (std::int64_t) buf.f_bsize * (std::int64_t) buf.f_blocks;
return 0;
}
String File::getVolumeLabel() const
{
#if BEAST_MAC
struct VolAttrBuf
{
u_int32_t length;
attrreference_t mountPointRef;
char mountPointSpace [MAXPATHLEN];
} attrBuf;
struct attrlist attrList;
zerostruct (attrList); // (can't use "= { 0 }" on this object because it's typedef'ed as a C struct)
attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_NAME;
File f (*this);
for (;;)
{
if (getattrlist (f.getFullPathName().toUTF8(), &attrList, &attrBuf, sizeof (attrBuf), 0) == 0)
return String::fromUTF8 (((const char*) &attrBuf.mountPointRef) + attrBuf.mountPointRef.attr_dataoffset,
(int) attrBuf.mountPointRef.attr_length);
const File parent (f.getParentDirectory());
if (f == parent)
break;
f = parent;
}
#endif
return String::empty;
}
int File::getVolumeSerialNumber() const
{
int result = 0;
/* int fd = open (getFullPathName().toUTF8(), O_RDONLY | O_NONBLOCK);
char info [512];
#ifndef HDIO_GET_IDENTITY
#define HDIO_GET_IDENTITY 0x030d
#endif
if (ioctl (fd, HDIO_GET_IDENTITY, info) == 0)
{
DBG (String (info + 20, 20));
result = String (info + 20, 20).trim().getIntValue();
}
close (fd);*/
return result;
}
//==============================================================================
void beast_runSystemCommand (const String&);
void beast_runSystemCommand (const String& command)
{
int result = system (command.toUTF8());
(void) result;
}
String beast_getOutputFromCommand (const String&);
String beast_getOutputFromCommand (const String& command)
{
// slight bodge here, as we just pipe the output into a temp file and read it...
const File tempFile (File::getSpecialLocation (File::tempDirectory)
.getNonexistentChildFile (String::toHexString (Random::getSystemRandom().nextInt()), ".tmp", false));
beast_runSystemCommand (command + " > " + tempFile.getFullPathName());
String result (tempFile.loadFileAsString());
tempFile.deleteFile();
return result;
}
//==============================================================================
bool DynamicLibrary::open (const String& name)
{
close();
handle = dlopen (name.isEmpty() ? nullptr : name.toUTF8().getAddress(), RTLD_LOCAL | RTLD_NOW);
return handle != nullptr;
}
void DynamicLibrary::close()
{
if (handle != nullptr)
{
dlclose (handle);
handle = nullptr;
}
}
void* DynamicLibrary::getFunction (const String& functionName) noexcept
{
return handle != nullptr ? dlsym (handle, functionName.toUTF8()) : nullptr;
}
} // beast

View File

@@ -0,0 +1,170 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_WIN32_COMSMARTPTR_H_INCLUDED
#define BEAST_WIN32_COMSMARTPTR_H_INCLUDED
namespace beast
{
#ifndef _MSC_VER
template<typename Type> struct UUIDGetter { static CLSID get() { bassertfalse; return CLSID(); } };
#define __uuidof(x) UUIDGetter<x>::get()
#endif
inline GUID uuidFromString (const char* const s) noexcept
{
unsigned long p0;
unsigned int p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;
#ifndef _MSC_VER
sscanf
#else
sscanf_s
#endif
(s, "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
&p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10);
GUID g = { p0, (std::uint16_t) p1, (std::uint16_t) p2, { (std::uint8_t) p3, (std::uint8_t) p4, (std::uint8_t) p5, (std::uint8_t) p6,
(std::uint8_t) p7, (std::uint8_t) p8, (std::uint8_t) p9, (std::uint8_t) p10 }};
return g;
}
//==============================================================================
/** A simple COM smart pointer.
*/
template <class ComClass>
class ComSmartPtr
{
public:
ComSmartPtr() throw() : p (0) {}
ComSmartPtr (ComClass* const obj) : p (obj) { if (p) p->AddRef(); }
ComSmartPtr (const ComSmartPtr<ComClass>& other) : p (other.p) { if (p) p->AddRef(); }
~ComSmartPtr() { release(); }
operator ComClass*() const throw() { return p; }
ComClass& operator*() const throw() { return *p; }
ComClass* operator->() const throw() { return p; }
ComSmartPtr& operator= (ComClass* const newP)
{
if (newP != 0) newP->AddRef();
release();
p = newP;
return *this;
}
ComSmartPtr& operator= (const ComSmartPtr<ComClass>& newP) { return operator= (newP.p); }
// Releases and nullifies this pointer and returns its address
ComClass** resetAndGetPointerAddress()
{
release();
p = 0;
return &p;
}
HRESULT CoCreateInstance (REFCLSID classUUID, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
{
HRESULT hr = ::CoCreateInstance (classUUID, 0, dwClsContext, __uuidof (ComClass), (void**) resetAndGetPointerAddress());
bassert (hr != CO_E_NOTINITIALIZED); // You haven't called CoInitialize for the current thread!
return hr;
}
template <class OtherComClass>
HRESULT QueryInterface (REFCLSID classUUID, ComSmartPtr<OtherComClass>& destObject) const
{
if (p == 0)
return E_POINTER;
return p->QueryInterface (classUUID, (void**) destObject.resetAndGetPointerAddress());
}
template <class OtherComClass>
HRESULT QueryInterface (ComSmartPtr<OtherComClass>& destObject) const
{
return this->QueryInterface (__uuidof (OtherComClass), destObject);
}
private:
ComClass* p;
void release() { if (p != 0) p->Release(); }
ComClass** operator&() throw(); // private to avoid it being used accidentally
};
//==============================================================================
#define BEAST_COMRESULT HRESULT __stdcall
//==============================================================================
template <class ComClass>
class ComBaseClassHelperBase : public ComClass
{
public:
ComBaseClassHelperBase (unsigned int initialRefCount) : refCount (initialRefCount) {}
virtual ~ComBaseClassHelperBase() {}
ULONG __stdcall AddRef() { return ++refCount; }
ULONG __stdcall Release() { const ULONG r = --refCount; if (r == 0) delete this; return r; }
protected:
ULONG refCount;
BEAST_COMRESULT QueryInterface (REFIID refId, void** result)
{
if (refId == IID_IUnknown)
return castToType <IUnknown> (result);
*result = 0;
return E_NOINTERFACE;
}
template <class Type>
BEAST_COMRESULT castToType (void** result)
{
this->AddRef(); *result = dynamic_cast <Type*> (this); return S_OK;
}
};
/** Handy base class for writing COM objects, providing ref-counting and a basic QueryInterface method.
*/
template <class ComClass>
class ComBaseClassHelper : public ComBaseClassHelperBase <ComClass>
{
public:
ComBaseClassHelper (unsigned int initialRefCount = 1) : ComBaseClassHelperBase <ComClass> (initialRefCount) {}
~ComBaseClassHelper() {}
BEAST_COMRESULT QueryInterface (REFIID refId, void** result)
{
if (refId == __uuidof (ComClass))
return this->template castToType <ComClass> (result);
return ComBaseClassHelperBase <ComClass>::QueryInterface (refId, result);
}
};
} // beast
#endif // BEAST_WIN32_COMSMARTPTR_H_INCLUDED

View File

@@ -0,0 +1,835 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
#ifndef INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES ((DWORD) -1)
#endif
//==============================================================================
namespace WindowsFileHelpers
{
DWORD getAtts (const String& path)
{
return GetFileAttributes (path.toWideCharPointer());
}
std::int64_t fileTimeToTime (const FILETIME* const ft)
{
static_bassert (sizeof (ULARGE_INTEGER) == sizeof (FILETIME)); // tell me if this fails!
return (std::int64_t) ((reinterpret_cast<const ULARGE_INTEGER*> (ft)->QuadPart - 116444736000000000LL) / 10000);
}
FILETIME* timeToFileTime (const std::int64_t time, FILETIME* const ft) noexcept
{
if (time <= 0)
return nullptr;
reinterpret_cast<ULARGE_INTEGER*> (ft)->QuadPart = (ULONGLONG) (time * 10000 + 116444736000000000LL);
return ft;
}
String getDriveFromPath (String path)
{
if (path.isNotEmpty() && path[1] == ':' && path[2] == 0)
path << '\\';
const size_t numBytes = CharPointer_UTF16::getBytesRequiredFor (path.getCharPointer()) + 4;
HeapBlock<WCHAR> pathCopy;
pathCopy.calloc (numBytes, 1);
path.copyToUTF16 (pathCopy, numBytes);
if (PathStripToRoot (pathCopy))
path = static_cast <const WCHAR*> (pathCopy);
return path;
}
std::int64_t getDiskSpaceInfo (const String& path, const bool total)
{
ULARGE_INTEGER spc, tot, totFree;
if (GetDiskFreeSpaceEx (getDriveFromPath (path).toWideCharPointer(), &spc, &tot, &totFree))
return total ? (std::int64_t) tot.QuadPart
: (std::int64_t) spc.QuadPart;
return 0;
}
unsigned int getWindowsDriveType (const String& path)
{
return GetDriveType (getDriveFromPath (path).toWideCharPointer());
}
File getSpecialFolderPath (int type)
{
WCHAR path [MAX_PATH + 256];
if (SHGetSpecialFolderPath (0, path, type, FALSE))
return File (String (path));
return File::nonexistent ();
}
File getModuleFileName (HINSTANCE moduleHandle)
{
WCHAR dest [MAX_PATH + 256];
dest[0] = 0;
GetModuleFileName (moduleHandle, dest, (DWORD) numElementsInArray (dest));
return File (String (dest));
}
Result getResultForLastError()
{
TCHAR messageBuffer [256] = { 0 };
FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, GetLastError(), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
messageBuffer, (DWORD) numElementsInArray (messageBuffer) - 1, nullptr);
return Result::fail (String (messageBuffer));
}
}
//==============================================================================
const beast_wchar File::separator = '\\';
const String File::separatorString ("\\");
//==============================================================================
bool File::exists() const
{
return fullPath.isNotEmpty()
&& WindowsFileHelpers::getAtts (fullPath) != INVALID_FILE_ATTRIBUTES;
}
bool File::existsAsFile() const
{
return fullPath.isNotEmpty()
&& (WindowsFileHelpers::getAtts (fullPath) & FILE_ATTRIBUTE_DIRECTORY) == 0;
}
bool File::isDirectory() const
{
const DWORD attr = WindowsFileHelpers::getAtts (fullPath);
return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) && (attr != INVALID_FILE_ATTRIBUTES);
}
bool File::hasWriteAccess() const
{
if (exists())
return (WindowsFileHelpers::getAtts (fullPath) & FILE_ATTRIBUTE_READONLY) == 0;
// on windows, it seems that even read-only directories can still be written into,
// so checking the parent directory's permissions would return the wrong result..
return true;
}
bool File::setFileReadOnlyInternal (const bool shouldBeReadOnly) const
{
const DWORD oldAtts = WindowsFileHelpers::getAtts (fullPath);
if (oldAtts == INVALID_FILE_ATTRIBUTES)
return false;
const DWORD newAtts = shouldBeReadOnly ? (oldAtts | FILE_ATTRIBUTE_READONLY)
: (oldAtts & ~FILE_ATTRIBUTE_READONLY);
return newAtts == oldAtts
|| SetFileAttributes (fullPath.toWideCharPointer(), newAtts) != FALSE;
}
bool File::isHidden() const
{
return (WindowsFileHelpers::getAtts (fullPath) & FILE_ATTRIBUTE_HIDDEN) != 0;
}
//==============================================================================
bool File::deleteFile() const
{
if (! exists())
return true;
return isDirectory() ? RemoveDirectory (fullPath.toWideCharPointer()) != 0
: DeleteFile (fullPath.toWideCharPointer()) != 0;
}
bool File::moveToTrash() const
{
if (! exists())
return true;
// The string we pass in must be double null terminated..
const size_t numBytes = CharPointer_UTF16::getBytesRequiredFor (fullPath.getCharPointer()) + 8;
HeapBlock<WCHAR> doubleNullTermPath;
doubleNullTermPath.calloc (numBytes, 1);
fullPath.copyToUTF16 (doubleNullTermPath, numBytes);
SHFILEOPSTRUCT fos = { 0 };
fos.wFunc = FO_DELETE;
fos.pFrom = doubleNullTermPath;
fos.fFlags = FOF_ALLOWUNDO | FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION
| FOF_NOCONFIRMMKDIR | FOF_RENAMEONCOLLISION;
return SHFileOperation (&fos) == 0;
}
bool File::copyInternal (const File& dest) const
{
return CopyFile (fullPath.toWideCharPointer(), dest.getFullPathName().toWideCharPointer(), false) != 0;
}
bool File::moveInternal (const File& dest) const
{
return MoveFile (fullPath.toWideCharPointer(), dest.getFullPathName().toWideCharPointer()) != 0;
}
Result File::createDirectoryInternal (const String& fileName) const
{
return CreateDirectory (fileName.toWideCharPointer(), 0) ? Result::ok()
: WindowsFileHelpers::getResultForLastError();
}
//==============================================================================
std::int64_t beast_fileSetPosition (void* handle, std::int64_t pos)
{
LARGE_INTEGER li;
li.QuadPart = pos;
li.LowPart = SetFilePointer ((HANDLE) handle, (LONG) li.LowPart, &li.HighPart, FILE_BEGIN); // (returns -1 if it fails)
return li.QuadPart;
}
void FileInputStream::openHandle()
{
HANDLE h = CreateFile (file.getFullPathName().toWideCharPointer(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
if (h != INVALID_HANDLE_VALUE)
fileHandle = (void*) h;
else
status = WindowsFileHelpers::getResultForLastError();
}
void FileInputStream::closeHandle()
{
CloseHandle ((HANDLE) fileHandle);
}
size_t FileInputStream::readInternal (void* buffer, size_t numBytes)
{
if (fileHandle != 0)
{
DWORD actualNum = 0;
if (! ReadFile ((HANDLE) fileHandle, buffer, (DWORD) numBytes, &actualNum, 0))
status = WindowsFileHelpers::getResultForLastError();
return (size_t) actualNum;
}
return 0;
}
//==============================================================================
void FileOutputStream::openHandle()
{
HANDLE h = CreateFile (file.getFullPathName().toWideCharPointer(), GENERIC_WRITE, FILE_SHARE_READ, 0,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (h != INVALID_HANDLE_VALUE)
{
LARGE_INTEGER li;
li.QuadPart = 0;
li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_END);
if (li.LowPart != INVALID_SET_FILE_POINTER)
{
fileHandle = (void*) h;
currentPosition = li.QuadPart;
return;
}
}
status = WindowsFileHelpers::getResultForLastError();
}
void FileOutputStream::closeHandle()
{
CloseHandle ((HANDLE) fileHandle);
}
std::ptrdiff_t FileOutputStream::writeInternal (const void* buffer, size_t numBytes)
{
if (fileHandle != nullptr)
{
DWORD actualNum = 0;
if (! WriteFile ((HANDLE) fileHandle, buffer, (DWORD) numBytes, &actualNum, 0))
status = WindowsFileHelpers::getResultForLastError();
return (std::ptrdiff_t) actualNum;
}
return 0;
}
void FileOutputStream::flushInternal()
{
if (fileHandle != nullptr)
if (! FlushFileBuffers ((HANDLE) fileHandle))
status = WindowsFileHelpers::getResultForLastError();
}
Result FileOutputStream::truncate()
{
if (fileHandle == nullptr)
return status;
flush();
return SetEndOfFile ((HANDLE) fileHandle) ? Result::ok()
: WindowsFileHelpers::getResultForLastError();
}
//==============================================================================
Result RandomAccessFile::nativeOpen (File const& path, Mode mode)
{
bassert (! isOpen ());
Result result (Result::ok ());
DWORD dwDesiredAccess;
switch (mode)
{
case readOnly:
dwDesiredAccess = GENERIC_READ;
break;
default:
case readWrite:
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
break;
};
DWORD dwCreationDisposition;
switch (mode)
{
case readOnly:
dwCreationDisposition = OPEN_EXISTING;
break;
default:
case readWrite:
dwCreationDisposition = OPEN_ALWAYS;
break;
};
HANDLE h = CreateFile (path.getFullPathName().toWideCharPointer(),
dwDesiredAccess,
FILE_SHARE_READ,
0,
dwCreationDisposition,
FILE_ATTRIBUTE_NORMAL,
0);
if (h != INVALID_HANDLE_VALUE)
{
file = path;
fileHandle = h;
result = setPosition (0);
if (result.failed ())
nativeClose ();
}
else
{
result = WindowsFileHelpers::getResultForLastError();
}
return result;
}
void RandomAccessFile::nativeClose ()
{
bassert (isOpen ());
CloseHandle ((HANDLE) fileHandle);
file = File::nonexistent ();
fileHandle = nullptr;
currentPosition = 0;
}
Result RandomAccessFile::nativeSetPosition (FileOffset newPosition)
{
bassert (isOpen ());
Result result (Result::ok ());
LARGE_INTEGER li;
li.QuadPart = newPosition;
li.LowPart = SetFilePointer ((HANDLE) fileHandle,
(LONG) li.LowPart,
&li.HighPart,
FILE_BEGIN);
if (li.LowPart != INVALID_SET_FILE_POINTER)
{
currentPosition = li.QuadPart;
}
else
{
result = WindowsFileHelpers::getResultForLastError();
}
return result;
}
Result RandomAccessFile::nativeRead (void* buffer, ByteCount numBytes, ByteCount* pActualAmount)
{
bassert (isOpen ());
Result result (Result::ok ());
DWORD actualNum = 0;
if (! ReadFile ((HANDLE) fileHandle, buffer, (DWORD) numBytes, &actualNum, 0))
result = WindowsFileHelpers::getResultForLastError();
currentPosition += actualNum;
if (pActualAmount != nullptr)
*pActualAmount = actualNum;
return result;
}
Result RandomAccessFile::nativeWrite (void const* data, ByteCount numBytes, size_t* pActualAmount)
{
bassert (isOpen ());
Result result (Result::ok ());
DWORD actualNum = 0;
if (! WriteFile ((HANDLE) fileHandle, data, (DWORD) numBytes, &actualNum, 0))
result = WindowsFileHelpers::getResultForLastError();
if (pActualAmount != nullptr)
*pActualAmount = actualNum;
return result;
}
Result RandomAccessFile::nativeTruncate ()
{
bassert (isOpen ());
Result result (Result::ok ());
if (! SetEndOfFile ((HANDLE) fileHandle))
result = WindowsFileHelpers::getResultForLastError();
return result;
}
Result RandomAccessFile::nativeFlush ()
{
bassert (isOpen ());
Result result (Result::ok ());
if (! FlushFileBuffers ((HANDLE) fileHandle))
result = WindowsFileHelpers::getResultForLastError();
return result;
}
//==============================================================================
std::int64_t File::getSize() const
{
WIN32_FILE_ATTRIBUTE_DATA attributes;
if (GetFileAttributesEx (fullPath.toWideCharPointer(), GetFileExInfoStandard, &attributes))
return (((std::int64_t) attributes.nFileSizeHigh) << 32) | attributes.nFileSizeLow;
return 0;
}
void File::getFileTimesInternal (std::int64_t& modificationTime, std::int64_t& accessTime, std::int64_t& creationTime) const
{
using namespace WindowsFileHelpers;
WIN32_FILE_ATTRIBUTE_DATA attributes;
if (GetFileAttributesEx (fullPath.toWideCharPointer(), GetFileExInfoStandard, &attributes))
{
modificationTime = fileTimeToTime (&attributes.ftLastWriteTime);
creationTime = fileTimeToTime (&attributes.ftCreationTime);
accessTime = fileTimeToTime (&attributes.ftLastAccessTime);
}
else
{
creationTime = accessTime = modificationTime = 0;
}
}
bool File::setFileTimesInternal (std::int64_t modificationTime, std::int64_t accessTime, std::int64_t creationTime) const
{
using namespace WindowsFileHelpers;
bool ok = false;
HANDLE h = CreateFile (fullPath.toWideCharPointer(), GENERIC_WRITE, FILE_SHARE_READ, 0,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (h != INVALID_HANDLE_VALUE)
{
FILETIME m, a, c;
ok = SetFileTime (h,
timeToFileTime (creationTime, &c),
timeToFileTime (accessTime, &a),
timeToFileTime (modificationTime, &m)) != 0;
CloseHandle (h);
}
return ok;
}
//==============================================================================
void File::findFileSystemRoots (Array<File>& destArray)
{
TCHAR buffer [2048] = { 0 };
GetLogicalDriveStrings (2048, buffer);
const TCHAR* n = buffer;
StringArray roots;
while (*n != 0)
{
roots.add (String (n));
while (*n++ != 0)
{}
}
roots.sort (true);
for (int i = 0; i < roots.size(); ++i)
destArray.add (roots [i]);
}
//==============================================================================
String File::getVolumeLabel() const
{
TCHAR dest[64];
if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toWideCharPointer(), dest,
(DWORD) numElementsInArray (dest), 0, 0, 0, 0, 0))
dest[0] = 0;
return dest;
}
int File::getVolumeSerialNumber() const
{
TCHAR dest[64];
DWORD serialNum;
if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toWideCharPointer(), dest,
(DWORD) numElementsInArray (dest), &serialNum, 0, 0, 0, 0))
return 0;
return (int) serialNum;
}
std::int64_t File::getBytesFreeOnVolume() const
{
return WindowsFileHelpers::getDiskSpaceInfo (getFullPathName(), false);
}
std::int64_t File::getVolumeTotalSize() const
{
return WindowsFileHelpers::getDiskSpaceInfo (getFullPathName(), true);
}
//==============================================================================
bool File::isOnCDRomDrive() const
{
return WindowsFileHelpers::getWindowsDriveType (getFullPathName()) == DRIVE_CDROM;
}
bool File::isOnHardDisk() const
{
if (fullPath.isEmpty())
return false;
const unsigned int n = WindowsFileHelpers::getWindowsDriveType (getFullPathName());
if (fullPath.toLowerCase()[0] <= 'b' && fullPath[1] == ':')
return n != DRIVE_REMOVABLE;
return n != DRIVE_CDROM && n != DRIVE_REMOTE;
}
bool File::isOnRemovableDrive() const
{
if (fullPath.isEmpty())
return false;
const unsigned int n = WindowsFileHelpers::getWindowsDriveType (getFullPathName());
return n == DRIVE_CDROM
|| n == DRIVE_REMOTE
|| n == DRIVE_REMOVABLE
|| n == DRIVE_RAMDISK;
}
//==============================================================================
File File::getSpecialLocation (const SpecialLocationType type)
{
int csidlType = 0;
switch (type)
{
case userHomeDirectory: csidlType = CSIDL_PROFILE; break;
case userDocumentsDirectory: csidlType = CSIDL_PERSONAL; break;
case userDesktopDirectory: csidlType = CSIDL_DESKTOP; break;
case userApplicationDataDirectory: csidlType = CSIDL_APPDATA; break;
case commonApplicationDataDirectory: csidlType = CSIDL_COMMON_APPDATA; break;
case commonDocumentsDirectory: csidlType = CSIDL_COMMON_DOCUMENTS; break;
case globalApplicationsDirectory: csidlType = CSIDL_PROGRAM_FILES; break;
case userMusicDirectory: csidlType = 0x0d; /*CSIDL_MYMUSIC*/ break;
case userMoviesDirectory: csidlType = 0x0e; /*CSIDL_MYVIDEO*/ break;
case userPicturesDirectory: csidlType = 0x27; /*CSIDL_MYPICTURES*/ break;
case tempDirectory:
{
WCHAR dest [2048];
dest[0] = 0;
GetTempPath ((DWORD) numElementsInArray (dest), dest);
return File (String (dest));
}
case invokedExecutableFile:
case currentExecutableFile:
case currentApplicationFile:
return WindowsFileHelpers::getModuleFileName ((HINSTANCE) Process::getCurrentModuleInstanceHandle());
case hostApplicationPath:
return WindowsFileHelpers::getModuleFileName (0);
default:
bassertfalse; // unknown type?
return File::nonexistent ();
}
return WindowsFileHelpers::getSpecialFolderPath (csidlType);
}
//==============================================================================
File File::getCurrentWorkingDirectory()
{
WCHAR dest [MAX_PATH + 256];
dest[0] = 0;
GetCurrentDirectory ((DWORD) numElementsInArray (dest), dest);
return File (String (dest));
}
bool File::setAsCurrentWorkingDirectory() const
{
return SetCurrentDirectory (getFullPathName().toWideCharPointer()) != FALSE;
}
//==============================================================================
String File::getVersion() const
{
String result;
DWORD handle = 0;
DWORD bufferSize = GetFileVersionInfoSize (getFullPathName().toWideCharPointer(), &handle);
HeapBlock<char> buffer;
buffer.calloc (bufferSize);
if (GetFileVersionInfo (getFullPathName().toWideCharPointer(), 0, bufferSize, buffer))
{
VS_FIXEDFILEINFO* vffi;
UINT len = 0;
if (VerQueryValue (buffer, (LPTSTR) _T("\\"), (LPVOID*) &vffi, &len))
{
result << (int) HIWORD (vffi->dwFileVersionMS) << '.'
<< (int) LOWORD (vffi->dwFileVersionMS) << '.'
<< (int) HIWORD (vffi->dwFileVersionLS) << '.'
<< (int) LOWORD (vffi->dwFileVersionLS);
}
}
return result;
}
//==============================================================================
File File::getLinkedTarget() const
{
File result (*this);
String p (getFullPathName());
if (! exists())
p += ".lnk";
else if (! hasFileExtension (".lnk"))
return result;
ComSmartPtr <IShellLink> shellLink;
ComSmartPtr <IPersistFile> persistFile;
if (SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink))
&& SUCCEEDED (shellLink.QueryInterface (persistFile))
&& SUCCEEDED (persistFile->Load (p.toWideCharPointer(), STGM_READ))
&& SUCCEEDED (shellLink->Resolve (0, SLR_ANY_MATCH | SLR_NO_UI)))
{
WIN32_FIND_DATA winFindData;
WCHAR resolvedPath [MAX_PATH];
if (SUCCEEDED (shellLink->GetPath (resolvedPath, MAX_PATH, &winFindData, SLGP_UNCPRIORITY)))
result = File (resolvedPath);
}
return result;
}
bool File::createLink (const String& description, const File& linkFileToCreate) const
{
linkFileToCreate.deleteFile();
ComSmartPtr <IShellLink> shellLink;
ComSmartPtr <IPersistFile> persistFile;
return SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink))
&& SUCCEEDED (shellLink->SetPath (getFullPathName().toWideCharPointer()))
&& SUCCEEDED (shellLink->SetDescription (description.toWideCharPointer()))
&& SUCCEEDED (shellLink.QueryInterface (persistFile))
&& SUCCEEDED (persistFile->Save (linkFileToCreate.getFullPathName().toWideCharPointer(), TRUE));
}
//==============================================================================
class DirectoryIterator::NativeIterator::Pimpl
: LeakChecked <DirectoryIterator::NativeIterator::Pimpl>
, public Uncopyable
{
public:
Pimpl (const File& directory, const String& wildCard)
: directoryWithWildCard (File::addTrailingSeparator (directory.getFullPathName()) + wildCard),
handle (INVALID_HANDLE_VALUE)
{
}
~Pimpl()
{
if (handle != INVALID_HANDLE_VALUE)
FindClose (handle);
}
bool next (String& filenameFound,
bool* const isDir, bool* const isHidden, std::int64_t* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
using namespace WindowsFileHelpers;
WIN32_FIND_DATA findData;
if (handle == INVALID_HANDLE_VALUE)
{
handle = FindFirstFile (directoryWithWildCard.toWideCharPointer(), &findData);
if (handle == INVALID_HANDLE_VALUE)
return false;
}
else
{
if (FindNextFile (handle, &findData) == 0)
return false;
}
filenameFound = findData.cFileName;
if (isDir != nullptr) *isDir = ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
if (isHidden != nullptr) *isHidden = ((findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0);
if (isReadOnly != nullptr) *isReadOnly = ((findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
if (fileSize != nullptr) *fileSize = findData.nFileSizeLow + (((std::int64_t) findData.nFileSizeHigh) << 32);
if (modTime != nullptr) *modTime = Time (fileTimeToTime (&findData.ftLastWriteTime));
if (creationTime != nullptr) *creationTime = Time (fileTimeToTime (&findData.ftCreationTime));
return true;
}
private:
const String directoryWithWildCard;
HANDLE handle;
};
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
{
}
DirectoryIterator::NativeIterator::~NativeIterator()
{
}
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
bool* const isDir, bool* const isHidden, std::int64_t* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
}
//==============================================================================
bool Process::openDocument (const String& fileName, const String& parameters)
{
HINSTANCE hInstance = 0;
hInstance = ShellExecute (0, 0, fileName.toWideCharPointer(),
parameters.toWideCharPointer(), 0, SW_SHOWDEFAULT);
return hInstance > (HINSTANCE) 32;
}
void File::revealToUser() const
{
DynamicLibrary dll ("Shell32.dll");
BEAST_LOAD_WINAPI_FUNCTION (dll, ILCreateFromPathW, ilCreateFromPathW, ITEMIDLIST*, (LPCWSTR))
BEAST_LOAD_WINAPI_FUNCTION (dll, ILFree, ilFree, void, (ITEMIDLIST*))
BEAST_LOAD_WINAPI_FUNCTION (dll, SHOpenFolderAndSelectItems, shOpenFolderAndSelectItems, HRESULT, (ITEMIDLIST*, UINT, void*, DWORD))
if (ilCreateFromPathW != nullptr && shOpenFolderAndSelectItems != nullptr && ilFree != nullptr)
{
if (ITEMIDLIST* const itemIDList = ilCreateFromPathW (fullPath.toWideCharPointer()))
{
shOpenFolderAndSelectItems (itemIDList, 0, nullptr, 0);
ilFree (itemIDList);
}
}
}
} // beast

View File

@@ -0,0 +1,219 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
struct RegistryKeyWrapper : public Uncopyable
{
RegistryKeyWrapper (String name, const bool createForWriting, const DWORD wow64Flags)
: key (0), wideCharValueName (nullptr)
{
HKEY rootKey = 0;
if (name.startsWithIgnoreCase ("HKEY_CURRENT_USER\\")) rootKey = HKEY_CURRENT_USER;
else if (name.startsWithIgnoreCase ("HKEY_LOCAL_MACHINE\\")) rootKey = HKEY_LOCAL_MACHINE;
else if (name.startsWithIgnoreCase ("HKEY_CLASSES_ROOT\\")) rootKey = HKEY_CLASSES_ROOT;
if (rootKey != 0)
{
name = name.substring (name.indexOfChar ('\\') + 1);
const int lastSlash = name.lastIndexOfChar ('\\');
valueName = name.substring (lastSlash + 1);
wideCharValueName = valueName.toWideCharPointer();
name = name.substring (0, lastSlash);
const wchar_t* const wideCharName = name.toWideCharPointer();
DWORD result;
if (createForWriting)
RegCreateKeyEx (rootKey, wideCharName, 0, 0, REG_OPTION_NON_VOLATILE,
KEY_WRITE | KEY_QUERY_VALUE | wow64Flags, 0, &key, &result);
else
RegOpenKeyEx (rootKey, wideCharName, 0, KEY_READ | wow64Flags, &key);
}
}
~RegistryKeyWrapper()
{
if (key != 0)
RegCloseKey (key);
}
static bool setValue (const String& regValuePath, const DWORD type,
const void* data, size_t dataSize)
{
const RegistryKeyWrapper key (regValuePath, true, 0);
return key.key != 0
&& RegSetValueEx (key.key, key.wideCharValueName, 0, type,
reinterpret_cast <const BYTE*> (data),
(DWORD) dataSize) == ERROR_SUCCESS;
}
static std::uint32_t getBinaryValue (const String& regValuePath, MemoryBlock& result, DWORD wow64Flags)
{
const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
if (key.key != 0)
{
for (unsigned long bufferSize = 1024; ; bufferSize *= 2)
{
result.setSize (bufferSize, false);
DWORD type = REG_NONE;
const LONG err = RegQueryValueEx (key.key, key.wideCharValueName, 0, &type,
(LPBYTE) result.getData(), &bufferSize);
if (err == ERROR_SUCCESS)
{
result.setSize (bufferSize, false);
return type;
}
if (err != ERROR_MORE_DATA)
break;
}
}
return REG_NONE;
}
static String getValue (const String& regValuePath, const String& defaultValue, DWORD wow64Flags)
{
MemoryBlock buffer;
switch (getBinaryValue (regValuePath, buffer, wow64Flags))
{
case REG_SZ: return static_cast <const WCHAR*> (buffer.getData());
case REG_DWORD: return String ((int) *reinterpret_cast<const DWORD*> (buffer.getData()));
default: break;
}
return defaultValue;
}
static bool valueExists (const String& regValuePath, const DWORD wow64Flags)
{
const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
if (key.key == 0)
return false;
unsigned char buffer [512];
unsigned long bufferSize = sizeof (buffer);
DWORD type = 0;
const LONG result = RegQueryValueEx (key.key, key.wideCharValueName,
0, &type, buffer, &bufferSize);
return result == ERROR_SUCCESS || result == ERROR_MORE_DATA;
}
HKEY key;
const wchar_t* wideCharValueName;
String valueName;
};
std::uint32_t WindowsRegistry::getBinaryValue (const String& regValuePath, MemoryBlock& result)
{
return RegistryKeyWrapper::getBinaryValue (regValuePath, result, 0);
}
String WindowsRegistry::getValue (const String& regValuePath, const String& defaultValue)
{
return RegistryKeyWrapper::getValue (regValuePath, defaultValue, 0);
}
String WindowsRegistry::getValueWow64 (const String& regValuePath, const String& defaultValue)
{
return RegistryKeyWrapper::getValue (regValuePath, defaultValue, 0x100 /*KEY_WOW64_64KEY*/);
}
bool WindowsRegistry::valueExistsWow64 (const String& regValuePath)
{
return RegistryKeyWrapper::valueExists (regValuePath, 0x100 /*KEY_WOW64_64KEY*/);
}
bool WindowsRegistry::setValue (const String& regValuePath, const String& value)
{
return RegistryKeyWrapper::setValue (regValuePath, REG_SZ, value.toWideCharPointer(),
CharPointer_UTF16::getBytesRequiredFor (value.getCharPointer()));
}
bool WindowsRegistry::setValue (const String& regValuePath, const std::uint32_t value)
{
return RegistryKeyWrapper::setValue (regValuePath, REG_DWORD, &value, sizeof (value));
}
bool WindowsRegistry::setValue (const String& regValuePath, const std::uint64_t value)
{
return RegistryKeyWrapper::setValue (regValuePath, REG_QWORD, &value, sizeof (value));
}
bool WindowsRegistry::setValue (const String& regValuePath, const MemoryBlock& value)
{
return RegistryKeyWrapper::setValue (regValuePath, REG_BINARY, value.getData(), value.getSize());
}
bool WindowsRegistry::valueExists (const String& regValuePath)
{
return RegistryKeyWrapper::valueExists (regValuePath, 0);
}
void WindowsRegistry::deleteValue (const String& regValuePath)
{
const RegistryKeyWrapper key (regValuePath, true, 0);
if (key.key != 0)
RegDeleteValue (key.key, key.wideCharValueName);
}
void WindowsRegistry::deleteKey (const String& regKeyPath)
{
const RegistryKeyWrapper key (regKeyPath, true, 0);
if (key.key != 0)
RegDeleteKey (key.key, key.wideCharValueName);
}
bool WindowsRegistry::registerFileAssociation (const String& fileExtension,
const String& symbolicDescription,
const String& fullDescription,
const File& targetExecutable,
const int iconResourceNumber,
const bool registerForCurrentUserOnly)
{
const char* const root = registerForCurrentUserOnly ? "HKEY_CURRENT_USER\\Software\\Classes\\"
: "HKEY_CLASSES_ROOT\\";
const String key (root + symbolicDescription);
return setValue (root + fileExtension + "\\", symbolicDescription)
&& setValue (key + "\\", fullDescription)
&& setValue (key + "\\shell\\open\\command\\", targetExecutable.getFullPathName() + " \"%1\"")
&& (iconResourceNumber == 0
|| setValue (key + "\\DefaultIcon\\",
targetExecutable.getFullPathName() + "," + String (-iconResourceNumber)));
}
} // beast

View File

@@ -0,0 +1,423 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
void Logger::outputDebugString (const String& text)
{
OutputDebugString ((text + "\n").toWideCharPointer());
}
//==============================================================================
#ifdef BEAST_DLL_BUILD
void* beastDLL_malloc (size_t sz) { return std::malloc (sz); }
void beastDLL_free (void* block) { std::free (block); }
#endif
//==============================================================================
#if BEAST_USE_INTRINSICS
// CPU info functions using intrinsics...
#pragma intrinsic (__cpuid)
#pragma intrinsic (__rdtsc)
String SystemStats::getCpuVendor()
{
int info [4];
__cpuid (info, 0);
char v [12];
memcpy (v, info + 1, 4);
memcpy (v + 4, info + 3, 4);
memcpy (v + 8, info + 2, 4);
return String (v, 12);
}
#else
//==============================================================================
// CPU info functions using old fashioned inline asm...
static void beast_getCpuVendor (char* const v)
{
int vendor[4] = { 0 };
#if ! BEAST_MINGW
__try
#endif
{
#if BEAST_GCC
unsigned int dummy = 0;
__asm__ ("cpuid" : "=a" (dummy), "=b" (vendor[0]), "=c" (vendor[2]),"=d" (vendor[1]) : "a" (0));
#else
__asm
{
mov eax, 0
cpuid
mov [vendor], ebx
mov [vendor + 4], edx
mov [vendor + 8], ecx
}
#endif
}
#if ! BEAST_MINGW
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
#endif
memcpy (v, vendor, 16);
}
String SystemStats::getCpuVendor()
{
char v [16];
beast_getCpuVendor (v);
return String (v, 16);
}
#endif
//==============================================================================
void CPUInformation::initialise() noexcept
{
hasMMX = IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE) != 0;
hasSSE = IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0;
hasSSE2 = IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0;
hasSSE3 = IsProcessorFeaturePresent (13 /*PF_SSE3_INSTRUCTIONS_AVAILABLE*/) != 0;
has3DNow = IsProcessorFeaturePresent (7 /*PF_AMD3D_INSTRUCTIONS_AVAILABLE*/) != 0;
SYSTEM_INFO systemInfo;
GetNativeSystemInfo (&systemInfo);
numCpus = (int) systemInfo.dwNumberOfProcessors;
}
//==============================================================================
static bool isWindowsVersionOrLater (SystemStats::OperatingSystemType target)
{
OSVERSIONINFOEX info;
zerostruct (info);
info.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
if (target >= SystemStats::WinVista)
{
info.dwMajorVersion = 6;
switch (target)
{
case SystemStats::WinVista: info.dwMinorVersion = 0; break;
case SystemStats::Windows7: info.dwMinorVersion = 1; break;
case SystemStats::Windows8: info.dwMinorVersion = 2; break;
default: bassertfalse; break;
}
}
else
{
info.dwMajorVersion = 5;
info.dwMinorVersion = target >= SystemStats::WinXP ? 1 : 0;
}
DWORDLONG mask = 0;
VER_SET_CONDITION (mask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION (mask, VER_MINORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION (mask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
VER_SET_CONDITION (mask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
return VerifyVersionInfo (&info,
VER_MAJORVERSION | VER_MINORVERSION
| VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
mask) != FALSE;
}
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
{
const SystemStats::OperatingSystemType types[]
= { Windows8, Windows7, WinVista, WinXP, Win2000 };
for (int i = 0; i < numElementsInArray (types); ++i)
if (isWindowsVersionOrLater (types[i]))
return types[i];
bassertfalse; // need to support whatever new version is running!
return UnknownOS;
}
String SystemStats::getOperatingSystemName()
{
const char* name = "Unknown OS";
switch (getOperatingSystemType())
{
case Windows7: name = "Windows 7"; break;
case Windows8: name = "Windows 8"; break;
case WinVista: name = "Windows Vista"; break;
case WinXP: name = "Windows XP"; break;
case Win2000: name = "Windows 2000"; break;
default: bassertfalse; break; // !! new type of OS?
}
return name;
}
bool SystemStats::isOperatingSystem64Bit()
{
#if BEAST_64BIT
return true;
#else
typedef BOOL (WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process
= (LPFN_ISWOW64PROCESS) GetProcAddress (GetModuleHandleA ("kernel32"), "IsWow64Process");
BOOL isWow64 = FALSE;
return fnIsWow64Process != nullptr
&& fnIsWow64Process (GetCurrentProcess(), &isWow64)
&& isWow64 != FALSE;
#endif
}
//==============================================================================
int SystemStats::getMemorySizeInMegabytes()
{
MEMORYSTATUSEX mem;
mem.dwLength = sizeof (mem);
GlobalMemoryStatusEx (&mem);
return (int) (mem.ullTotalPhys / (1024 * 1024)) + 1;
}
//==============================================================================
String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue)
{
DWORD len = GetEnvironmentVariableW (name.toWideCharPointer(), nullptr, 0);
if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
return String (defaultValue);
HeapBlock<WCHAR> buffer (len);
len = GetEnvironmentVariableW (name.toWideCharPointer(), buffer, len);
return String (CharPointer_wchar_t (buffer),
CharPointer_wchar_t (buffer + len));
}
//==============================================================================
std::uint32_t beast_millisecondsSinceStartup() noexcept
{
return (std::uint32_t) timeGetTime();
}
//==============================================================================
class HiResCounterHandler
{
public:
HiResCounterHandler()
: hiResTicksOffset (0)
{
const MMRESULT res = timeBeginPeriod (1);
(void) res;
bassert (res == TIMERR_NOERROR);
LARGE_INTEGER f;
QueryPerformanceFrequency (&f);
hiResTicksPerSecond = f.QuadPart;
hiResTicksScaleFactor = 1000.0 / hiResTicksPerSecond;
}
inline std::int64_t getHighResolutionTicks() noexcept
{
LARGE_INTEGER ticks;
QueryPerformanceCounter (&ticks);
const std::int64_t mainCounterAsHiResTicks = (beast_millisecondsSinceStartup() * hiResTicksPerSecond) / 1000;
const std::int64_t newOffset = mainCounterAsHiResTicks - ticks.QuadPart;
// fix for a very obscure PCI hardware bug that can make the counter
// sometimes jump forwards by a few seconds..
const std::int64_t offsetDrift = abs64 (newOffset - hiResTicksOffset);
if (offsetDrift > (hiResTicksPerSecond >> 1))
hiResTicksOffset = newOffset;
return ticks.QuadPart + hiResTicksOffset;
}
inline double getMillisecondCounterHiRes() noexcept
{
return getHighResolutionTicks() * hiResTicksScaleFactor;
}
std::int64_t hiResTicksPerSecond, hiResTicksOffset;
double hiResTicksScaleFactor;
};
static HiResCounterHandler hiResCounterHandler;
std::int64_t Time::getHighResolutionTicksPerSecond() noexcept { return hiResCounterHandler.hiResTicksPerSecond; }
std::int64_t Time::getHighResolutionTicks() noexcept { return hiResCounterHandler.getHighResolutionTicks(); }
double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterHandler.getMillisecondCounterHiRes(); }
//==============================================================================
static std::int64_t beast_getClockCycleCounter() noexcept
{
#if BEAST_USE_INTRINSICS
// MS intrinsics version...
return (std::int64_t) __rdtsc();
#elif BEAST_GCC
// GNU inline asm version...
unsigned int hi = 0, lo = 0;
__asm__ __volatile__ (
"xor %%eax, %%eax \n\
xor %%edx, %%edx \n\
rdtsc \n\
movl %%eax, %[lo] \n\
movl %%edx, %[hi]"
:
: [hi] "m" (hi),
[lo] "m" (lo)
: "cc", "eax", "ebx", "ecx", "edx", "memory");
return (std::int64_t) ((((std::uint64_t) hi) << 32) | lo);
#else
// MSVC inline asm version...
unsigned int hi = 0, lo = 0;
__asm
{
xor eax, eax
xor edx, edx
rdtsc
mov lo, eax
mov hi, edx
}
return (std::int64_t) ((((std::uint64_t) hi) << 32) | lo);
#endif
}
int SystemStats::getCpuSpeedInMegaherz()
{
const std::int64_t cycles = beast_getClockCycleCounter();
const std::uint32_t millis = Time::getMillisecondCounter();
int lastResult = 0;
for (;;)
{
int n = 1000000;
while (--n > 0) {}
const std::uint32_t millisElapsed = Time::getMillisecondCounter() - millis;
const std::int64_t cyclesNow = beast_getClockCycleCounter();
if (millisElapsed > 80)
{
const int newResult = (int) (((cyclesNow - cycles) / millisElapsed) / 1000);
if (millisElapsed > 500 || (lastResult == newResult && newResult > 100))
return newResult;
lastResult = newResult;
}
}
}
//==============================================================================
bool Time::setSystemTimeToThisTime() const
{
SYSTEMTIME st;
st.wDayOfWeek = 0;
st.wYear = (WORD) getYear();
st.wMonth = (WORD) (getMonth() + 1);
st.wDay = (WORD) getDayOfMonth();
st.wHour = (WORD) getHours();
st.wMinute = (WORD) getMinutes();
st.wSecond = (WORD) getSeconds();
st.wMilliseconds = (WORD) (millisSinceEpoch % 1000);
// do this twice because of daylight saving conversion problems - the
// first one sets it up, the second one kicks it in.
return SetLocalTime (&st) != 0
&& SetLocalTime (&st) != 0;
}
int SystemStats::getPageSize()
{
SYSTEM_INFO systemInfo;
GetNativeSystemInfo (&systemInfo);
return (int) systemInfo.dwPageSize;
}
//==============================================================================
String SystemStats::getLogonName()
{
TCHAR text [256] = { 0 };
DWORD len = (DWORD) numElementsInArray (text) - 1;
GetUserName (text, &len);
return String (text, len);
}
String SystemStats::getFullUserName()
{
return getLogonName();
}
String SystemStats::getComputerName()
{
TCHAR text [MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
DWORD len = (DWORD) numElementsInArray (text) - 1;
GetComputerName (text, &len);
return String (text, len);
}
static String getLocaleValue (LCID locale, LCTYPE key, const char* defaultValue)
{
TCHAR buffer [256] = { 0 };
if (GetLocaleInfo (locale, key, buffer, 255) > 0)
return buffer;
return defaultValue;
}
String SystemStats::getUserLanguage() { return getLocaleValue (LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, "en"); }
String SystemStats::getUserRegion() { return getLocaleValue (LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, "US"); }
String SystemStats::getDisplayLanguage()
{
DynamicLibrary dll ("kernel32.dll");
BEAST_LOAD_WINAPI_FUNCTION (dll, GetUserDefaultUILanguage, getUserDefaultUILanguage, LANGID, (void))
if (getUserDefaultUILanguage != nullptr)
return getLocaleValue (MAKELCID (getUserDefaultUILanguage(), SORT_DEFAULT), LOCALE_SISO639LANGNAME, "en");
return "en";
}
} // beast

View File

@@ -0,0 +1,189 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
void* getUser32Function (const char* functionName)
{
HMODULE module = GetModuleHandleA ("user32.dll");
bassert (module != 0);
return (void*) GetProcAddress (module, functionName);
}
//==============================================================================
#if ! BEAST_USE_INTRINSICS
// In newer compilers, the inline versions of these are used (in beast_Atomic.h), but in
// older ones we have to actually call the ops as win32 functions..
long beast_InterlockedExchange (volatile long* a, long b) noexcept { return InterlockedExchange (a, b); }
long beast_InterlockedIncrement (volatile long* a) noexcept { return InterlockedIncrement (a); }
long beast_InterlockedDecrement (volatile long* a) noexcept { return InterlockedDecrement (a); }
long beast_InterlockedExchangeAdd (volatile long* a, long b) noexcept { return InterlockedExchangeAdd (a, b); }
long beast_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept { return InterlockedCompareExchange (a, b, c); }
__int64 beast_InterlockedCompareExchange64 (volatile __int64* value, __int64 newValue, __int64 valueToCompare) noexcept
{
bassertfalse; // This operation isn't available in old MS compiler versions!
__int64 oldValue = *value;
if (oldValue == valueToCompare)
*value = newValue;
return oldValue;
}
#endif
//==============================================================================
CriticalSection::CriticalSection() noexcept
{
// (just to check the MS haven't changed this structure and broken things...)
#if BEAST_VC7_OR_EARLIER
static_bassert (sizeof (CRITICAL_SECTION) <= 24);
#else
static_bassert (sizeof (CRITICAL_SECTION) <= sizeof (section));
#endif
InitializeCriticalSection ((CRITICAL_SECTION*) section);
}
CriticalSection::~CriticalSection() noexcept { DeleteCriticalSection ((CRITICAL_SECTION*) section); }
void CriticalSection::enter() const noexcept { EnterCriticalSection ((CRITICAL_SECTION*) section); }
bool CriticalSection::tryEnter() const noexcept { return TryEnterCriticalSection ((CRITICAL_SECTION*) section) != FALSE; }
void CriticalSection::exit() const noexcept { LeaveCriticalSection ((CRITICAL_SECTION*) section); }
//==============================================================================
static int lastProcessPriority = -1;
// called by WindowDriver because Windows does weird things to process priority
// when you swap apps, and this forces an update when the app is brought to the front.
void beast_repeatLastProcessPriority()
{
if (lastProcessPriority >= 0) // (avoid changing this if it's not been explicitly set by the app..)
{
DWORD p;
switch (lastProcessPriority)
{
case Process::LowPriority: p = IDLE_PRIORITY_CLASS; break;
case Process::NormalPriority: p = NORMAL_PRIORITY_CLASS; break;
case Process::HighPriority: p = HIGH_PRIORITY_CLASS; break;
case Process::RealtimePriority: p = REALTIME_PRIORITY_CLASS; break;
default: bassertfalse; return; // bad priority value
}
SetPriorityClass (GetCurrentProcess(), p);
}
}
void Process::setPriority (ProcessPriority prior)
{
if (lastProcessPriority != (int) prior)
{
lastProcessPriority = (int) prior;
beast_repeatLastProcessPriority();
}
}
bool beast_isRunningUnderDebugger()
{
return IsDebuggerPresent() != FALSE;
}
bool Process::isRunningUnderDebugger()
{
return beast_isRunningUnderDebugger();
}
//------------------------------------------------------------------------------
static void* currentModuleHandle = nullptr;
void* Process::getCurrentModuleInstanceHandle() noexcept
{
if (currentModuleHandle == nullptr)
currentModuleHandle = GetModuleHandleA (nullptr);
return currentModuleHandle;
}
void Process::setCurrentModuleInstanceHandle (void* const newHandle) noexcept
{
currentModuleHandle = newHandle;
}
void Process::raisePrivilege()
{
bassertfalse; // xxx not implemented
}
void Process::lowerPrivilege()
{
bassertfalse; // xxx not implemented
}
void Process::terminate()
{
#if BEAST_MSVC && BEAST_CHECK_MEMORY_LEAKS
_CrtDumpMemoryLeaks();
#endif
// bullet in the head in case there's a problem shutting down..
ExitProcess (0);
}
bool beast_isRunningInWine()
{
HMODULE ntdll = GetModuleHandleA ("ntdll");
return ntdll != 0 && GetProcAddress (ntdll, "wine_get_version") != nullptr;
}
//==============================================================================
bool DynamicLibrary::open (const String& name)
{
close();
handle = LoadLibrary (name.toWideCharPointer());
return handle != nullptr;
}
void DynamicLibrary::close()
{
if (handle != nullptr)
{
FreeLibrary ((HMODULE) handle);
handle = nullptr;
}
}
void* DynamicLibrary::getFunction (const String& functionName) noexcept
{
return handle != nullptr ? (void*) GetProcAddress ((HMODULE) handle, functionName.toUTF8()) // (void* cast is required for mingw)
: nullptr;
}
//==============================================================================
} // beast

View File

@@ -0,0 +1,56 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
FileInputSource::FileInputSource (const File& f, bool useFileTimeInHash)
: file (f), useFileTimeInHashGeneration (useFileTimeInHash)
{
}
FileInputSource::~FileInputSource()
{
}
InputStream* FileInputSource::createInputStream()
{
return file.createInputStream();
}
InputStream* FileInputSource::createInputStreamFor (const String& relatedItemPath)
{
return file.getSiblingFile (relatedItemPath).createInputStream();
}
std::int64_t FileInputSource::hashCode() const
{
std::int64_t h = file.hashCode();
if (useFileTimeInHashGeneration)
h ^= file.getLastModificationTime().toMilliseconds();
return h;
}
} // beast

View File

@@ -0,0 +1,65 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_FILEINPUTSOURCE_H_INCLUDED
#define BEAST_FILEINPUTSOURCE_H_INCLUDED
namespace beast
{
//==============================================================================
/**
A type of InputSource that represents a normal file.
@see InputSource
*/
class FileInputSource
: public InputSource
, LeakChecked <FileInputSource>
, public Uncopyable
{
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();
InputStream* createInputStream();
InputStream* createInputStreamFor (const String& relatedItemPath);
std::int64_t hashCode() const;
private:
//==============================================================================
const File file;
bool useFileTimeInHashGeneration;
};
} // beast
#endif // BEAST_FILEINPUTSOURCE_H_INCLUDED

View File

@@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_INPUTSOURCE_H_INCLUDED
#define BEAST_INPUTSOURCE_H_INCLUDED
namespace beast
{
//==============================================================================
/**
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
*/
class InputSource : LeakChecked <InputSource>
{
public:
//==============================================================================
InputSource() noexcept {}
/** Destructor. */
virtual ~InputSource() {}
//==============================================================================
/** 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 std::int64_t hashCode() const = 0;
};
} // beast
#endif // BEAST_INPUTSOURCE_H_INCLUDED

View File

@@ -0,0 +1,326 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
std::int64_t InputStream::getNumBytesRemaining()
{
std::int64_t len = getTotalLength();
if (len >= 0)
len -= getPosition();
return len;
}
char InputStream::readByte()
{
char temp = 0;
read (&temp, 1);
return temp;
}
bool InputStream::readBool()
{
return readByte() != 0;
}
short InputStream::readShort()
{
char temp[2];
if (read (temp, 2) == 2)
return (short) ByteOrder::littleEndianShort (temp);
return 0;
}
short InputStream::readShortBigEndian()
{
char temp[2];
if (read (temp, 2) == 2)
return (short) ByteOrder::bigEndianShort (temp);
return 0;
}
int InputStream::readInt()
{
static_bassert (sizeof (int) == 4);
char temp[4];
if (read (temp, 4) == 4)
return (int) ByteOrder::littleEndianInt (temp);
return 0;
}
std::int32_t InputStream::readInt32()
{
char temp[4];
if (read (temp, 4) == 4)
return (std::int32_t) ByteOrder::littleEndianInt (temp);
return 0;
}
int InputStream::readIntBigEndian()
{
char temp[4];
if (read (temp, 4) == 4)
return (int) ByteOrder::bigEndianInt (temp);
return 0;
}
std::int32_t InputStream::readInt32BigEndian()
{
char temp[4];
if (read (temp, 4) == 4)
return (std::int32_t) ByteOrder::bigEndianInt (temp);
return 0;
}
int InputStream::readCompressedInt()
{
const std::uint8_t sizeByte = (std::uint8_t) readByte();
if (sizeByte == 0)
return 0;
const int numBytes = (sizeByte & 0x7f);
if (numBytes > 4)
{
bassertfalse; // trying to read corrupt data - this method must only be used
// to read data that was written by OutputStream::writeCompressedInt()
return 0;
}
char bytes[4] = { 0, 0, 0, 0 };
if (read (bytes, numBytes) != numBytes)
return 0;
const int num = (int) ByteOrder::littleEndianInt (bytes);
return (sizeByte >> 7) ? -num : num;
}
std::int64_t InputStream::readInt64()
{
union { std::uint8_t asBytes[8]; std::uint64_t asInt64; } n;
if (read (n.asBytes, 8) == 8)
return (std::int64_t) ByteOrder::swapIfBigEndian (n.asInt64);
return 0;
}
std::int64_t InputStream::readInt64BigEndian()
{
union { std::uint8_t asBytes[8]; std::uint64_t asInt64; } n;
if (read (n.asBytes, 8) == 8)
return (std::int64_t) ByteOrder::swapIfLittleEndian (n.asInt64);
return 0;
}
float InputStream::readFloat()
{
// the union below relies on these types being the same size...
static_bassert (sizeof (std::int32_t) == sizeof (float));
union { std::int32_t asInt; float asFloat; } n;
n.asInt = (std::int32_t) readInt();
return n.asFloat;
}
float InputStream::readFloatBigEndian()
{
union { std::int32_t asInt; float asFloat; } n;
n.asInt = (std::int32_t) readIntBigEndian();
return n.asFloat;
}
double InputStream::readDouble()
{
union { std::int64_t asInt; double asDouble; } n;
n.asInt = readInt64();
return n.asDouble;
}
double InputStream::readDoubleBigEndian()
{
union { std::int64_t asInt; double asDouble; } n;
n.asInt = readInt64BigEndian();
return n.asDouble;
}
String InputStream::readString()
{
MemoryBlock buffer (256);
char* data = static_cast<char*> (buffer.getData());
size_t i = 0;
while ((data[i] = readByte()) != 0)
{
if (++i >= buffer.getSize())
{
buffer.setSize (buffer.getSize() + 512);
data = static_cast<char*> (buffer.getData());
}
}
return String (CharPointer_UTF8 (data),
CharPointer_UTF8 (data + i));
}
String InputStream::readNextLine()
{
MemoryBlock buffer (256);
char* data = static_cast<char*> (buffer.getData());
size_t i = 0;
while ((data[i] = readByte()) != 0)
{
if (data[i] == '\n')
break;
if (data[i] == '\r')
{
const std::int64_t lastPos = getPosition();
if (readByte() != '\n')
setPosition (lastPos);
break;
}
if (++i >= buffer.getSize())
{
buffer.setSize (buffer.getSize() + 512);
data = static_cast<char*> (buffer.getData());
}
}
return String::fromUTF8 (data, (int) i);
}
int InputStream::readIntoMemoryBlock (MemoryBlock& block, std::ptrdiff_t numBytes)
{
MemoryOutputStream mo (block, true);
return mo.writeFromInputStream (*this, numBytes);
}
String InputStream::readEntireStreamAsString()
{
MemoryOutputStream mo;
mo << *this;
return mo.toString();
}
//==============================================================================
void InputStream::skipNextBytes (std::int64_t numBytesToSkip)
{
if (numBytesToSkip > 0)
{
const int skipBufferSize = (int) bmin (numBytesToSkip, (std::int64_t) 16384);
HeapBlock<char> temp ((size_t) skipBufferSize);
while (numBytesToSkip > 0 && ! isExhausted())
numBytesToSkip -= read (temp, (int) bmin (numBytesToSkip, (std::int64_t) skipBufferSize));
}
}
//------------------------------------------------------------------------------
// Unfortunately, putting these in the header causes duplicate
// definition linker errors, even with the inline keyword!
template <>
char InputStream::readType <char> () { return readByte (); }
template <>
short InputStream::readType <short> () { return readShort (); }
template <>
std::int32_t InputStream::readType <std::int32_t> () { return readInt32 (); }
template <>
std::int64_t InputStream::readType <std::int64_t> () { return readInt64 (); }
template <>
unsigned char InputStream::readType <unsigned char> () { return static_cast <unsigned char> (readByte ()); }
template <>
unsigned short InputStream::readType <unsigned short> () { return static_cast <unsigned short> (readShort ()); }
template <>
std::uint32_t InputStream::readType <std::uint32_t> () { return static_cast <std::uint32_t> (readInt32 ()); }
template <>
std::uint64_t InputStream::readType <std::uint64_t> () { return static_cast <std::uint64_t> (readInt64 ()); }
template <>
float InputStream::readType <float> () { return readFloat (); }
template <>
double InputStream::readType <double> () { return readDouble (); }
//------------------------------------------------------------------------------
template <>
char InputStream::readTypeBigEndian <char> () { return readByte (); }
template <>
short InputStream::readTypeBigEndian <short> () { return readShortBigEndian (); }
template <>
std::int32_t InputStream::readTypeBigEndian <std::int32_t> () { return readInt32BigEndian (); }
template <>
std::int64_t InputStream::readTypeBigEndian <std::int64_t> () { return readInt64BigEndian (); }
template <>
unsigned char InputStream::readTypeBigEndian <unsigned char> () { return static_cast <unsigned char> (readByte ()); }
template <>
unsigned short InputStream::readTypeBigEndian <unsigned short> () { return static_cast <unsigned short> (readShortBigEndian ()); }
template <>
std::uint32_t InputStream::readTypeBigEndian <std::uint32_t> () { return static_cast <std::uint32_t> (readInt32BigEndian ()); }
template <>
std::uint64_t InputStream::readTypeBigEndian <std::uint64_t> () { return static_cast <std::uint64_t> (readInt64BigEndian ()); }
template <>
float InputStream::readTypeBigEndian <float> () { return readFloatBigEndian (); }
template <>
double InputStream::readTypeBigEndian <double> () { return readDoubleBigEndian (); }
} // beast

View File

@@ -0,0 +1,360 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_INPUTSTREAM_H_INCLUDED
#define BEAST_INPUTSTREAM_H_INCLUDED
namespace beast
{
class MemoryBlock;
//==============================================================================
/** 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, FileInputStream
*/
class InputStream
: public Uncopyable
, LeakChecked <InputStream>
{
public:
/** Destructor. */
virtual ~InputStream() {}
//==============================================================================
/** 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 std::int64_t getTotalLength() = 0;
/** Returns the number of bytes available for reading, or a negative value if
the remaining length is not known.
@see getTotalLength
*/
std::int64_t 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;
/** 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();
// VFALCO TODO Implement these functions
//virtual std::int16_t readInt16 ();
//virtual std::uint16_t readUInt16 ();
/** 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::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 std::int32_t readInt32();
// VFALCO TODO Implement these functions
//virtual std::int16_t readInt16BigEndian ();
//virtual std::uint16_t readUInt16BigEndian ();
// DEPRECATED, assumes sizeof(int) == 4!
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 std::int32_t readInt32BigEndian();
// DEPRECATED, assumes sizeof(int) == 4!
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 std::int64_t 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 std::int64_t 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 std::int64_t.
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 std::int64_t.
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 type using a template specialization.
This is useful when doing template meta-programming.
*/
template <class T>
T readType ();
/** Reads a type using a template specialization.
The variable is passed as a parameter so that the template type
can be deduced. The return value indicates whether or not there
was sufficient data in the stream to read the value.
*/
template <class T>
bool readTypeInto (T* p)
{
if (getNumBytesRemaining () >= sizeof (T))
{
*p = readType <T> ();
return true;
}
return false;
}
/** Reads a type from a big endian stream using a template specialization.
The raw encoding of the type is read from the stream as a big-endian value
where applicable.
This is useful when doing template meta-programming.
*/
template <class T>
T readTypeBigEndian ();
/** Reads a type using a template specialization.
The variable is passed as a parameter so that the template type
can be deduced. The return value indicates whether or not there
was sufficient data in the stream to read the value.
*/
template <class T>
bool readTypeBigEndianInto (T* p)
{
if (getNumBytesRemaining () >= sizeof (T))
{
*p = readTypeBigEndian <T> ();
return true;
}
return false;
}
//==============================================================================
/** 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 either UTF-16 or UTF-8 formats.
*/
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 int readIntoMemoryBlock (MemoryBlock& destBlock,
std::ptrdiff_t maxNumBytesToRead = -1);
//==============================================================================
/** Returns the offset of the next byte that will be read from the stream.
@see setPosition
*/
virtual std::int64_t 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 (std::int64_t newPosition) = 0;
/** Reads and discards a number of bytes from the stream.
Some input streams might implement this efficiently, but the base
class will just keep reading data until the requisite number of bytes
have been done.
*/
virtual void skipNextBytes (std::int64_t numBytesToSkip);
protected:
//==============================================================================
InputStream() noexcept {}
};
} // beast
#endif

View File

@@ -0,0 +1,214 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
MemoryOutputStream::MemoryOutputStream (const size_t initialSize)
: blockToUse (&internalBlock), externalData (nullptr),
position (0), size (0), availableSize (0)
{
internalBlock.setSize (initialSize, false);
}
MemoryOutputStream::MemoryOutputStream (MemoryBlock& memoryBlockToWriteTo,
const bool appendToExistingBlockContent)
: blockToUse (&memoryBlockToWriteTo), externalData (nullptr),
position (0), size (0), availableSize (0)
{
if (appendToExistingBlockContent)
position = size = memoryBlockToWriteTo.getSize();
}
MemoryOutputStream::MemoryOutputStream (void* destBuffer, size_t destBufferSize)
: blockToUse (nullptr), externalData (destBuffer),
position (0), size (0), availableSize (destBufferSize)
{
bassert (externalData != nullptr); // This must be a valid pointer.
}
MemoryOutputStream::~MemoryOutputStream()
{
trimExternalBlockSize();
}
void MemoryOutputStream::flush()
{
trimExternalBlockSize();
}
void MemoryOutputStream::trimExternalBlockSize()
{
if (blockToUse != &internalBlock && blockToUse != nullptr)
blockToUse->setSize (size, false);
}
void MemoryOutputStream::preallocate (const size_t bytesToPreallocate)
{
if (blockToUse != nullptr)
blockToUse->ensureSize (bytesToPreallocate + 1);
}
void MemoryOutputStream::reset() noexcept
{
position = 0;
size = 0;
}
char* MemoryOutputStream::prepareToWrite (size_t numBytes)
{
bassert ((std::ptrdiff_t) numBytes >= 0);
size_t storageNeeded = position + numBytes;
char* data;
if (blockToUse != nullptr)
{
if (storageNeeded >= blockToUse->getSize())
blockToUse->ensureSize ((storageNeeded + bmin (storageNeeded / 2, (size_t) (1024 * 1024)) + 32) & ~31u);
data = static_cast <char*> (blockToUse->getData());
}
else
{
if (storageNeeded > availableSize)
return nullptr;
data = static_cast <char*> (externalData);
}
char* const writePointer = data + position;
position += numBytes;
size = bmax (size, position);
return writePointer;
}
bool MemoryOutputStream::write (const void* const buffer, size_t howMany)
{
bassert (buffer != nullptr);
if (howMany == 0)
return true;
if (char* dest = prepareToWrite (howMany))
{
memcpy (dest, buffer, howMany);
return true;
}
return false;
}
bool MemoryOutputStream::writeRepeatedByte (std::uint8_t byte, size_t howMany)
{
if (howMany == 0)
return true;
if (char* dest = prepareToWrite (howMany))
{
memset (dest, byte, howMany);
return true;
}
return false;
}
bool MemoryOutputStream::appendUTF8Char (beast_wchar c)
{
if (char* dest = prepareToWrite (CharPointer_UTF8::getBytesRequiredFor (c)))
{
CharPointer_UTF8 (dest).write (c);
return true;
}
return false;
}
MemoryBlock MemoryOutputStream::getMemoryBlock() const
{
return MemoryBlock (getData(), getDataSize());
}
const void* MemoryOutputStream::getData() const noexcept
{
if (blockToUse == nullptr)
return externalData;
if (blockToUse->getSize() > size)
static_cast <char*> (blockToUse->getData()) [size] = 0;
return blockToUse->getData();
}
bool MemoryOutputStream::setPosition (std::int64_t newPosition)
{
if (newPosition <= (std::int64_t) size)
{
// ok to seek backwards
position = blimit ((size_t) 0, size, (size_t) newPosition);
return true;
}
// can't move beyond the end of the stream..
return false;
}
int MemoryOutputStream::writeFromInputStream (InputStream& source, std::int64_t maxNumBytesToWrite)
{
// before writing from an input, see if we can preallocate to make it more efficient..
std::int64_t availableData = source.getTotalLength() - source.getPosition();
if (availableData > 0)
{
if (maxNumBytesToWrite > availableData)
maxNumBytesToWrite = availableData;
if (blockToUse != nullptr)
preallocate (blockToUse->getSize() + (size_t) maxNumBytesToWrite);
}
return OutputStream::writeFromInputStream (source, maxNumBytesToWrite);
}
String MemoryOutputStream::toUTF8() const
{
const char* const d = static_cast <const char*> (getData());
return String (CharPointer_UTF8 (d), CharPointer_UTF8 (d + getDataSize()));
}
String MemoryOutputStream::toString() const
{
return String::createStringFromData (getData(), (int) getDataSize());
}
OutputStream& operator<< (OutputStream& stream, const MemoryOutputStream& streamToRead)
{
const size_t dataSize = streamToRead.getDataSize();
if (dataSize > 0)
stream.write (streamToRead.getData(), dataSize);
return stream;
}
} // beast

View File

@@ -0,0 +1,145 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_MEMORYOUTPUTSTREAM_H_INCLUDED
#define BEAST_MEMORYOUTPUTSTREAM_H_INCLUDED
namespace beast
{
//==============================================================================
/**
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.
*/
//==============================================================================
/**
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.
*/
class MemoryOutputStream
: public OutputStream
, LeakChecked <MemoryOutputStream>
{
public:
//==============================================================================
/** Creates an empty memory stream, ready to be written into.
@param initialSize the intial 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 capactity 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();
//==============================================================================
/** 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 (beast_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();
bool write (const void*, size_t) override;
std::int64_t getPosition() override { return position; }
bool setPosition (std::int64_t) override;
int writeFromInputStream (InputStream&, std::int64_t maxNumBytesToWrite) override;
bool writeRepeatedByte (std::uint8_t byte, size_t numTimesToRepeat) override;
private:
void trimExternalBlockSize();
char* prepareToWrite (size_t);
//==============================================================================
MemoryBlock* const blockToUse;
MemoryBlock internalBlock;
void* externalData;
size_t position, size, availableSize;
};
/** Copies all the data that has been written to a MemoryOutputStream into another stream. */
OutputStream& operator<< (OutputStream& stream, const MemoryOutputStream& streamToRead);
} // beast
#endif

View File

@@ -0,0 +1,438 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
#if BEAST_DEBUG
struct DanglingStreamChecker
{
DanglingStreamChecker() {}
~DanglingStreamChecker()
{
/*
It's always a bad idea to leak any object, but if you're leaking output
streams, then there's a good chance that you're failing to flush a file
to disk properly, which could result in corrupted data and other similar
nastiness..
*/
bassert (activeStreams.size() == 0);
}
Array<void*, CriticalSection> activeStreams;
};
static DanglingStreamChecker danglingStreamChecker;
#endif
//==============================================================================
OutputStream::OutputStream()
: newLineString (NewLine::getDefault())
{
#if BEAST_DEBUG
danglingStreamChecker.activeStreams.add (this);
#endif
}
OutputStream::~OutputStream()
{
#if BEAST_DEBUG
danglingStreamChecker.activeStreams.removeFirstMatchingValue (this);
#endif
}
//==============================================================================
bool OutputStream::writeBool (const bool b)
{
return writeByte (b ? (char) 1
: (char) 0);
}
bool OutputStream::writeByte (char byte)
{
return write (&byte, 1);
}
bool OutputStream::writeRepeatedByte (std::uint8_t byte, size_t numTimesToRepeat)
{
for (size_t i = 0; i < numTimesToRepeat; ++i)
if (! writeByte ((char) byte))
return false;
return true;
}
bool OutputStream::writeShort (short value)
{
const unsigned short v = ByteOrder::swapIfBigEndian ((unsigned short) value);
return write (&v, 2);
}
bool OutputStream::writeShortBigEndian (short value)
{
const unsigned short v = ByteOrder::swapIfLittleEndian ((unsigned short) value);
return write (&v, 2);
}
bool OutputStream::writeInt32 (std::int32_t value)
{
static_bassert (sizeof (std::int32_t) == 4);
const unsigned int v = ByteOrder::swapIfBigEndian ((std::uint32_t) value);
return write (&v, 4);
}
bool OutputStream::writeInt (int value)
{
static_bassert (sizeof (int) == 4);
const unsigned int v = ByteOrder::swapIfBigEndian ((unsigned int) value);
return write (&v, 4);
}
bool OutputStream::writeInt32BigEndian (int value)
{
static_bassert (sizeof (std::int32_t) == 4);
const std::uint32_t v = ByteOrder::swapIfLittleEndian ((std::uint32_t) value);
return write (&v, 4);
}
bool OutputStream::writeIntBigEndian (int value)
{
static_bassert (sizeof (int) == 4);
const unsigned int v = ByteOrder::swapIfLittleEndian ((unsigned int) value);
return write (&v, 4);
}
bool OutputStream::writeCompressedInt (int value)
{
unsigned int un = (value < 0) ? (unsigned int) -value
: (unsigned int) value;
std::uint8_t data[5];
int num = 0;
while (un > 0)
{
data[++num] = (std::uint8_t) un;
un >>= 8;
}
data[0] = (std::uint8_t) num;
if (value < 0)
data[0] |= 0x80;
return write (data, (size_t) num + 1);
}
bool OutputStream::writeInt64 (std::int64_t value)
{
const std::uint64_t v = ByteOrder::swapIfBigEndian ((std::uint64_t) value);
return write (&v, 8);
}
bool OutputStream::writeInt64BigEndian (std::int64_t value)
{
const std::uint64_t v = ByteOrder::swapIfLittleEndian ((std::uint64_t) value);
return write (&v, 8);
}
bool OutputStream::writeFloat (float value)
{
union { int asInt; float asFloat; } n;
n.asFloat = value;
return writeInt (n.asInt);
}
bool OutputStream::writeFloatBigEndian (float value)
{
union { int asInt; float asFloat; } n;
n.asFloat = value;
return writeIntBigEndian (n.asInt);
}
bool OutputStream::writeDouble (double value)
{
union { std::int64_t asInt; double asDouble; } n;
n.asDouble = value;
return writeInt64 (n.asInt);
}
bool OutputStream::writeDoubleBigEndian (double value)
{
union { std::int64_t asInt; double asDouble; } n;
n.asDouble = value;
return writeInt64BigEndian (n.asInt);
}
bool OutputStream::writeString (const String& text)
{
// (This avoids using toUTF8() to prevent the memory bloat that it would leave behind
// if lots of large, persistent strings were to be written to streams).
const size_t numBytes = text.getNumBytesAsUTF8() + 1;
HeapBlock<char> temp (numBytes);
text.copyToUTF8 (temp, numBytes);
return write (temp, numBytes);
}
bool OutputStream::writeText (const String& text, const bool asUTF16,
const bool writeUTF16ByteOrderMark)
{
if (asUTF16)
{
if (writeUTF16ByteOrderMark)
write ("\x0ff\x0fe", 2);
String::CharPointerType src (text.getCharPointer());
bool lastCharWasReturn = false;
for (;;)
{
const beast_wchar c = src.getAndAdvance();
if (c == 0)
break;
if (c == '\n' && ! lastCharWasReturn)
writeShort ((short) '\r');
lastCharWasReturn = (c == L'\r');
if (! writeShort ((short) c))
return false;
}
}
else
{
const char* src = text.toUTF8();
const char* t = src;
for (;;)
{
if (*t == '\n')
{
if (t > src)
if (! write (src, (size_t) (t - src)))
return false;
if (! write ("\r\n", 2))
return false;
src = t + 1;
}
else if (*t == '\r')
{
if (t[1] == '\n')
++t;
}
else if (*t == 0)
{
if (t > src)
if (! write (src, (size_t) (t - src)))
return false;
break;
}
++t;
}
}
return true;
}
int OutputStream::writeFromInputStream (InputStream& source, std::int64_t numBytesToWrite)
{
if (numBytesToWrite < 0)
numBytesToWrite = std::numeric_limits<std::int64_t>::max();
int numWritten = 0;
while (numBytesToWrite > 0)
{
char buffer [8192];
const int num = source.read (buffer, (int) bmin (numBytesToWrite, (std::int64_t) sizeof (buffer)));
if (num <= 0)
break;
write (buffer, (size_t) num);
numBytesToWrite -= num;
numWritten += num;
}
return numWritten;
}
//==============================================================================
void OutputStream::setNewLineString (const String& newLineString_)
{
newLineString = newLineString_;
}
//==============================================================================
OutputStream& operator<< (OutputStream& stream, const int number)
{
return stream << String (number);
}
OutputStream& operator<< (OutputStream& stream, const std::int64_t number)
{
return stream << String (number);
}
OutputStream& operator<< (OutputStream& stream, const double number)
{
return stream << String (number);
}
OutputStream& operator<< (OutputStream& stream, const char character)
{
stream.writeByte (character);
return stream;
}
OutputStream& operator<< (OutputStream& stream, const char* const text)
{
stream.write (text, strlen (text));
return stream;
}
OutputStream& operator<< (OutputStream& stream, const MemoryBlock& data)
{
if (data.getSize() > 0)
stream.write (data.getData(), data.getSize());
return stream;
}
OutputStream& operator<< (OutputStream& stream, const File& fileToRead)
{
FileInputStream in (fileToRead);
if (in.openedOk())
return stream << in;
return stream;
}
OutputStream& operator<< (OutputStream& stream, InputStream& streamToRead)
{
stream.writeFromInputStream (streamToRead, -1);
return stream;
}
OutputStream& operator<< (OutputStream& stream, const NewLine&)
{
return stream << stream.getNewLineString();
}
//------------------------------------------------------------------------------
// Unfortunately, putting these in the header causes duplicate
// definition linker errors, even with the inline keyword!
template <>
bool OutputStream::writeType <char> (char v) { return writeByte (v); }
template <>
bool OutputStream::writeType <short> (short v) { return writeShort (v); }
template <>
bool OutputStream::writeType <std::int32_t> (std::int32_t v) { return writeInt32 (v); }
template <>
bool OutputStream::writeType <std::int64_t> (std::int64_t v) { return writeInt64 (v); }
template <>
bool OutputStream::writeType <unsigned char> (unsigned char v) { return writeByte (static_cast <char> (v)); }
template <>
bool OutputStream::writeType <unsigned short> (unsigned short v) { return writeShort (static_cast <short> (v)); }
template <>
bool OutputStream::writeType <std::uint32_t> (std::uint32_t v) { return writeInt32 (static_cast <std::int32_t> (v)); }
template <>
bool OutputStream::writeType <std::uint64_t> (std::uint64_t v) { return writeInt64 (static_cast <std::int64_t> (v)); }
template <>
bool OutputStream::writeType <float> (float v) { return writeFloat (v); }
template <>
bool OutputStream::writeType <double> (double v) { return writeDouble (v); }
//------------------------------------------------------------------------------
template <>
bool OutputStream::writeTypeBigEndian <char> (char v) { return writeByte (v); }
template <>
bool OutputStream::writeTypeBigEndian <short> (short v) { return writeShortBigEndian (v); }
template <>
bool OutputStream::writeTypeBigEndian <std::int32_t> (std::int32_t v) { return writeInt32BigEndian (v); }
template <>
bool OutputStream::writeTypeBigEndian <std::int64_t> (std::int64_t v) { return writeInt64BigEndian (v); }
template <>
bool OutputStream::writeTypeBigEndian <unsigned char> (unsigned char v) { return writeByte (static_cast <char> (v)); }
template <>
bool OutputStream::writeTypeBigEndian <unsigned short> (unsigned short v) { return writeShortBigEndian (static_cast <short> (v)); }
template <>
bool OutputStream::writeTypeBigEndian <std::uint32_t> (std::uint32_t v) { return writeInt32BigEndian (static_cast <std::int32_t> (v)); }
template <>
bool OutputStream::writeTypeBigEndian <std::uint64_t> (std::uint64_t v) { return writeInt64BigEndian (static_cast <std::int64_t> (v)); }
template <>
bool OutputStream::writeTypeBigEndian <float> (float v) { return writeFloatBigEndian (v); }
template <>
bool OutputStream::writeTypeBigEndian <double> (double v) { return writeDoubleBigEndian (v); }
OutputStream& operator<< (OutputStream& stream, const String& text)
{
const size_t numBytes = text.getNumBytesAsUTF8();
#if (BEAST_STRING_UTF_TYPE == 8)
stream.write (text.getCharPointer().getAddress(), numBytes);
#else
// (This avoids using toUTF8() to prevent the memory bloat that it would leave behind
// if lots of large, persistent strings were to be written to streams).
HeapBlock<char> temp (numBytes + 1);
CharPointer_UTF8 (temp).writeAll (text.getCharPointer());
stream.write (temp, numBytes);
#endif
return stream;
}
} // beast

View File

@@ -0,0 +1,304 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_OUTPUTSTREAM_H_INCLUDED
#define BEAST_OUTPUTSTREAM_H_INCLUDED
namespace beast
{
class InputStream;
class MemoryBlock;
class File;
//==============================================================================
/**
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
*/
class OutputStream : public Uncopyable
{
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 (std::int64_t newPosition) = 0;
/** Returns the stream's current position.
@see setPosition
*/
virtual std::int64_t 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 writeInt32 (std::int32_t value);
// DEPRECATED, assumes sizeof (int) == 4!
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 writeInt32BigEndian (std::int32_t value);
// DEPRECATED, assumes sizeof (int) == 4!
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 (std::int64_t 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 (std::int64_t 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);
/** Write a type using a template specialization.
This is useful when doing template meta-programming.
*/
template <class T>
bool writeType (T value);
/** Write a type using a template specialization.
The raw encoding of the type is written to the stream as a big-endian value
where applicable.
This is useful when doing template meta-programming.
*/
template <class T>
bool writeTypeBigEndian (T 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 (std::uint8_t 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).
The method also replaces '\\n' characters in the text with '\\r\\n'.
@returns false if the write operation fails for some reason
*/
virtual bool writeText (const String& text,
bool asUTF16,
bool writeUTF16ByteOrderMark);
/** 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 int writeFromInputStream (InputStream& source, std::int64_t maxNumBytesToWrite);
//==============================================================================
/** Sets the string that will be written to the stream when the writeNewLine()
method is called.
By default this will be set the 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;
};
//==============================================================================
/** Writes a number to a stream as 8-bit characters in the default system encoding. */
OutputStream& operator<< (OutputStream& stream, int number);
/** Writes a number to a stream as 8-bit characters in the default system encoding. */
OutputStream& operator<< (OutputStream& stream, std::int64_t number);
/** Writes a number to a stream as 8-bit characters in the default system encoding. */
OutputStream& operator<< (OutputStream& stream, double number);
/** Writes a character to a stream. */
OutputStream& operator<< (OutputStream& stream, char character);
/** Writes a null-terminated text string to a stream. */
OutputStream& operator<< (OutputStream& stream, const char* text);
/** Writes a block of data from a MemoryBlock to a stream. */
OutputStream& operator<< (OutputStream& stream, const MemoryBlock& data);
/** Writes the contents of a file to a stream. */
OutputStream& operator<< (OutputStream& stream, const File& fileToRead);
/** Writes the complete contents of an input stream to an output stream. */
OutputStream& 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
*/
OutputStream& operator<< (OutputStream& stream, const NewLine&);
/** Writes a string to an OutputStream as UTF8. */
OutputStream& operator<< (OutputStream& stream, const String& stringToWrite);
} // beast
#endif

View File

@@ -0,0 +1,32 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CORE_SYSTEM_BEFOREBOOST_H_INCLUDED
#define BEAST_CORE_SYSTEM_BEFOREBOOST_H_INCLUDED
// TargetPlatform.h should not use anything from BeastConfig.h
#include <beast/Config.h>
// This file should be included before including any boost headers.
// If you don't include this file, and you include boost headers,
// Beast will generate a compile error with an explanation of why.
#include <beast/module/core/system/BoostPlaceholdersFix.h>
#endif

View File

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

View File

@@ -0,0 +1,42 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#if BEAST_USE_BOOST_FEATURES
namespace boost
{
namespace placeholders
{
boost::arg<1> _1;
boost::arg<2> _2;
boost::arg<3> _3;
boost::arg<4> _4;
boost::arg<5> _5;
boost::arg<6> _6;
boost::arg<7> _7;
boost::arg<8> _8;
boost::arg<9> _9;
}
}
#endif

View File

@@ -0,0 +1,64 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CORE_SYSTEM_BOOSTPLACEHOLDERSFIX_H_INCLUDED
#define BEAST_CORE_SYSTEM_BOOSTPLACEHOLDERSFIX_H_INCLUDED
#if BEAST_USE_BOOST_FEATURES
// Prevent <boost/bind/placeholders.hpp> from being included
#ifdef BOOST_BIND_PLACEHOLDERS_HPP_INCLUDED
# error "boost/bind.hpp must not be included before this file"
#else
# define BOOST_BIND_PLACEHOLDERS_HPP_INCLUDED
#endif
#include <boost/bind.hpp>
#include <boost/bind/arg.hpp>
// This is a hack to fix boost's goofy placeholders going into the global
// namespace. First we prevent the user from including boost/bind.hpp
// before us. Then we define the include guard macro and include
// boost/bind.hpp ourselves to get the declarations. Finally we repeat
// the missing placeholder declarations but put them in a proper namespace.
//
// We put the placeholders in boost::placeholders so they can be accessed
// explicitly to handle the common case of a "using namespace oost" directive
// being in effect.
//
// Declarations based on boost/bind/placeholders.cpp
//
namespace boost {
namespace placeholders {
extern boost::arg<1> _1;
extern boost::arg<2> _2;
extern boost::arg<3> _3;
extern boost::arg<4> _4;
extern boost::arg<5> _5;
extern boost::arg<6> _6;
extern boost::arg<7> _7;
extern boost::arg<8> _8;
extern boost::arg<9> _9;
}
using namespace placeholders;
}
#endif
#endif

View File

@@ -0,0 +1,381 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_FUNCTIONAL_H_INCLUDED
#define BEAST_FUNCTIONAL_H_INCLUDED
namespace beast
{
//------------------------------------------------------------------------------
/* Brings functional support into our namespace, based on environment.
Notes on bind
Difference between boost::bind and std::bind
http://stackoverflow.com/questions/10555566/is-there-any-difference-between-c11-stdbind-and-boostbind
Resolving conflict between boost::shared_ptr and std::shared_ptr
http://stackoverflow.com/questions/4682343/how-to-resolve-conflict-between-boostshared-ptr-and-using-stdshared-ptr
*/
#ifndef BEAST_BIND_PLACEHOLDERS_N
# if BEAST_MSVC && BEAST_FUNCTIONAL_USES_STD
# define BEAST_BIND_PLACEHOLDERS_N 20 // Visual Studio 2012
# else
# define BEAST_BIND_PLACEHOLDERS_N 8 // Seems a reasonable number
# endif
#endif
/** Max number of arguments to bind, total.
*/
#if BEAST_MSVC
# ifdef _VARIADIC_MAX
# define BEAST_VARIADIC_MAX _VARIADIC_MAX
# else
# define BEAST_VARIADIC_MAX 10
# endif
#else
# define BEAST_VARIADIC_MAX 10
#endif
//------------------------------------------------------------------------------
#if BEAST_FUNCTIONAL_USES_STD
namespace functional
{
using std::ref;
using std::cref;
using std::bind;
//using std::function;
}
using namespace functional;
namespace placeholders
{
#if BEAST_BIND_PLACEHOLDERS_N >= 1
using std::placeholders::_1;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 2
using std::placeholders::_2;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 3
using std::placeholders::_3;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 4
using std::placeholders::_4;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 5
using std::placeholders::_5;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 6
using std::placeholders::_6;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 7
using std::placeholders::_7;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 8
using std::placeholders::_8;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 9
using std::placeholders::_9;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 10
using std::placeholders::_10;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 11
using std::placeholders::_11;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 12
using std::placeholders::_12;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 13
using std::placeholders::_13;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 14
using std::placeholders::_14;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 15
using std::placeholders::_15;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 16
using std::placeholders::_16;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 17
using std::placeholders::_17;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 18
using std::placeholders::_18;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 19
using std::placeholders::_19;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 20
using std::placeholders::_20;
#endif
}
using namespace placeholders;
//------------------------------------------------------------------------------
#elif BEAST_FUNCTIONAL_USES_TR1
namespace functional
{
using std::tr1::ref;
using std::tr1::cref;
using std::tr1::bind;
//using std::tr1::function;
}
using namespace functional;
namespace placeholders
{
#if BEAST_BIND_PLACEHOLDERS_N >= 1
using std::tr1::placeholders::_1;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 2
using std::tr1::placeholders::_2;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 3
using std::tr1::placeholders::_3;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 4
using std::tr1::placeholders::_4;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 5
using std::tr1::placeholders::_5;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 6
using std::tr1::placeholders::_6;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 7
using std::tr1::placeholders::_7;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 8
using std::tr1::placeholders::_8;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 9
using std::tr1::placeholders::_9;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 10
using std::tr1::placeholders::_10;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 11
using std::tr1::placeholders::_11;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 12
using std::tr1::placeholders::_12;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 13
using std::tr1::placeholders::_13;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 14
using std::tr1::placeholders::_14;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 15
using std::tr1::placeholders::_15;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 16
using std::tr1::placeholders::_16;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 17
using std::tr1::placeholders::_17;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 18
using std::tr1::placeholders::_18;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 19
using std::tr1::placeholders::_19;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 20
using std::tr1::placeholders::_20;
#endif
}
using namespace placeholders;
//------------------------------------------------------------------------------
#elif BEAST_FUNCTIONAL_USES_BOOST
namespace functional
{
using boost::ref;
using boost::cref;
using boost::bind;
//using boost::function;
}
using namespace functional;
namespace placeholders
{
#if BEAST_BIND_PLACEHOLDERS_N >= 1
using boost::placeholders::_1;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 2
using boost::placeholders::_2;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 3
using boost::placeholders::_3;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 4
using boost::placeholders::_4;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 5
using boost::placeholders::_5;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 6
using boost::placeholders::_6;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 7
using boost::placeholders::_7;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 8
using boost::placeholders::_8;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 9
using boost::placeholders::_9;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 10
using boost::placeholders::_10;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 11
using boost::placeholders::_11;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 12
using boost::placeholders::_12;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 13
using boost::placeholders::_13;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 14
using boost::placeholders::_14;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 15
using boost::placeholders::_15;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 16
using boost::placeholders::_16;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 17
using boost::placeholders::_17;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 18
using boost::placeholders::_18;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 19
using boost::placeholders::_19;
#endif
#if BEAST_BIND_PLACEHOLDERS_N >= 20
using boost::placeholders::_20;
#endif
}
using namespace placeholders;
//------------------------------------------------------------------------------
#else
#error Unknown bind source in Functional.h
#endif
} // beast
#endif

View File

@@ -0,0 +1,54 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CORE_SYSTEM_FUNCTIONALINCLUDES_H_INCLUDED
#define BEAST_CORE_SYSTEM_FUNCTIONALINCLUDES_H_INCLUDED
// Choose a source of bind, placeholders, and function
#if !BEAST_FUNCTIONAL_USES_STD && !BEAST_FUNCTIONAL_USES_TR1 && !BEAST_FUNCTIONAL_USES_BOOST
# if BEAST_USE_BOOST_FEATURES
# define BEAST_FUNCTIONAL_USES_BOOST 1
# elif BEAST_MSVC
# define BEAST_FUNCTIONAL_USES_STD 1
# elif BEAST_IOS || BEAST_MAC
#include <ciso646> // detect version of std::lib
# if BEAST_IOS && BEAST_USE_BOOST_FEATURES // Work-around for iOS bugs with bind.
# define BEAST_FUNCTIONAL_USES_BOOST 1
# elif _LIBCPP_VERSION // libc++
# define BEAST_FUNCTIONAL_USES_STD 1
# else // libstdc++ (GNU)
# define BEAST_FUNCTIONAL_USES_TR1 1
# endif
# elif BEAST_LINUX || BEAST_BSD
# define BEAST_FUNCTIONAL_USES_TR1 1
# else
# define BEAST_FUNCTIONAL_USES_STD 1
# endif
#endif
#if BEAST_FUNCTIONAL_USES_STD
#include <functional>
#elif BEAST_FUNCTIONAL_USES_TR1
#include <tr1/functional>
#elif BEAST_FUNCTIONAL_USES_BOOST
// included in BoostPlaceholdersFix.h
#endif
#endif

View File

@@ -0,0 +1,78 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_STANDARDINCLUDES_H_INCLUDED
#define BEAST_STANDARDINCLUDES_H_INCLUDED
// Include some common OS headers..
#if BEAST_MSVC
#pragma warning (push)
#pragma warning (disable: 4514 4245 4100)
#endif
#include <algorithm>
#include <cfloat>
#include <climits>
#include <cmath>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cwchar>
#include <exception>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <map>
#include <new>
#include <numeric>
#include <ostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <typeinfo>
#include <vector>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <locale.h>
#include <math.h>
#include <memory.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// undef symbols that are sometimes set by misguided 3rd-party headers..
#undef check
#undef TYPE_BOOL
#undef max
#undef min
#endif

View File

@@ -0,0 +1,165 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
String SystemStats::getBeastVersion()
{
// Some basic tests, to keep an eye on things and make sure these types work ok
// on all platforms. Let me know if any of these assertions fail on your system!
static_bassert (sizeof (std::intptr_t) == sizeof (void*));
static_bassert (sizeof (std::int8_t) == 1);
static_bassert (sizeof (std::uint8_t) == 1);
static_bassert (sizeof (std::int16_t) == 2);
static_bassert (sizeof (std::uint16_t) == 2);
static_bassert (sizeof (std::int32_t) == 4);
static_bassert (sizeof (std::uint32_t) == 4);
static_bassert (sizeof (std::int64_t) == 8);
static_bassert (sizeof (std::uint64_t) == 8);
return "Beast v" BEAST_STRINGIFY(BEAST_MAJOR_VERSION)
"." BEAST_STRINGIFY(BEAST_MINOR_VERSION)
"." BEAST_STRINGIFY(BEAST_BUILDNUMBER);
}
//==============================================================================
struct CPUInformation
{
CPUInformation() noexcept
: numCpus (0), hasMMX (false), hasSSE (false),
hasSSE2 (false), hasSSE3 (false), has3DNow (false)
{
initialise();
}
void initialise() noexcept;
int numCpus;
bool hasMMX, hasSSE, hasSSE2, hasSSE3, has3DNow;
};
static const CPUInformation& getCPUInformation() noexcept
{
static CPUInformation info;
return info;
}
int SystemStats::getNumCpus() noexcept { return getCPUInformation().numCpus; }
bool SystemStats::hasMMX() noexcept { return getCPUInformation().hasMMX; }
bool SystemStats::hasSSE() noexcept { return getCPUInformation().hasSSE; }
bool SystemStats::hasSSE2() noexcept { return getCPUInformation().hasSSE2; }
bool SystemStats::hasSSE3() noexcept { return getCPUInformation().hasSSE3; }
bool SystemStats::has3DNow() noexcept { return getCPUInformation().has3DNow; }
//==============================================================================
String SystemStats::getStackBacktrace()
{
String result;
#if BEAST_ANDROID || BEAST_MINGW || BEAST_BSD
bassertfalse; // sorry, not implemented yet!
#elif BEAST_WINDOWS
HANDLE process = GetCurrentProcess();
SymInitialize (process, nullptr, TRUE);
void* stack[128];
int frames = (int) CaptureStackBackTrace (0, numElementsInArray (stack), stack, nullptr);
HeapBlock<SYMBOL_INFO> symbol;
symbol.calloc (sizeof (SYMBOL_INFO) + 256, 1);
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof (SYMBOL_INFO);
for (int i = 0; i < frames; ++i)
{
DWORD64 displacement = 0;
if (SymFromAddr (process, (DWORD64) stack[i], &displacement, symbol))
{
result << i << ": ";
IMAGEHLP_MODULE64 moduleInfo;
zerostruct (moduleInfo);
moduleInfo.SizeOfStruct = sizeof (moduleInfo);
if (::SymGetModuleInfo64 (process, symbol->ModBase, &moduleInfo))
result << moduleInfo.ModuleName << ": ";
result << symbol->Name << " + 0x" << String::toHexString ((std::int64_t) displacement) << newLine;
}
}
#else
void* stack[128];
int frames = backtrace (stack, numElementsInArray (stack));
char** frameStrings = backtrace_symbols (stack, frames);
for (int i = 0; i < frames; ++i)
result << frameStrings[i] << newLine;
::free (frameStrings);
#endif
return result;
}
//==============================================================================
static SystemStats::CrashHandlerFunction globalCrashHandler = nullptr;
#if BEAST_WINDOWS
static LONG WINAPI handleCrash (LPEXCEPTION_POINTERS)
{
globalCrashHandler();
return EXCEPTION_EXECUTE_HANDLER;
}
#else
static void handleCrash (int)
{
globalCrashHandler();
kill (getpid(), SIGKILL);
}
int beast_siginterrupt (int sig, int flag);
#endif
void SystemStats::setApplicationCrashHandler (CrashHandlerFunction handler)
{
bassert (handler != nullptr); // This must be a valid function.
globalCrashHandler = handler;
#if BEAST_WINDOWS
SetUnhandledExceptionFilter (handleCrash);
#else
const int signals[] = { SIGFPE, SIGILL, SIGSEGV, SIGBUS, SIGABRT, SIGSYS };
for (int i = 0; i < numElementsInArray (signals); ++i)
{
::signal (signals[i], handleCrash);
beast_siginterrupt (signals[i], 1);
}
#endif
}
} // beast

View File

@@ -0,0 +1,185 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SYSTEMSTATS_H_INCLUDED
#define BEAST_SYSTEMSTATS_H_INCLUDED
namespace beast
{
//==============================================================================
/**
Contains methods for finding out about the current hardware and OS configuration.
*/
class SystemStats : public Uncopyable
{
public:
//==============================================================================
/** Returns the current version of BEAST,
See also the BEAST_VERSION, BEAST_MAJOR_VERSION and BEAST_MINOR_VERSION macros.
*/
static String getBeastVersion();
//==============================================================================
/** The set of possible results of the getOperatingSystemType() method. */
enum OperatingSystemType
{
UnknownOS = 0,
MacOSX_10_4 = 0x1004,
MacOSX_10_5 = 0x1005,
MacOSX_10_6 = 0x1006,
MacOSX_10_7 = 0x1007,
MacOSX_10_8 = 0x1008,
Linux = 0x2000,
FreeBSD = 0x2001,
Android = 0x3000,
Win2000 = 0x4105,
WinXP = 0x4106,
WinVista = 0x4107,
Windows7 = 0x4108,
Windows8 = 0x4109,
Windows = 0x4000, /**< To test whether any version of Windows is running,
you can use the expression ((getOperatingSystemType() & Windows) != 0). */
iOS = 0x8000
};
/** 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)
*/
static String getDisplayLanguage();
//==============================================================================
// CPU and memory information..
/** Returns the number of CPU cores. */
static int getNumCpus() 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 getCpuSpeedInMegaherz();
/** Returns a string to indicate the CPU vendor.
Might not be known on some systems.
*/
static String getCpuVendor();
static bool hasMMX() noexcept; /**< Returns true if Intel MMX 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 SSE2 instructions are available. */
static bool has3DNow() noexcept; /**< Returns true if AMD 3DNOW 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 void() function type, used by setApplicationCrashHandler(). */
typedef void (*CrashHandlerFunction)();
/** 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);
private:
//==============================================================================
SystemStats();
};
} // beast
#endif // BEAST_SYSTEMSTATS_H_INCLUDED

View File

@@ -0,0 +1,106 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
namespace beast {
class LexicalCast_test : public unit_test::suite
{
public:
template <class IntType>
static IntType nextRandomInt (Random& r)
{
return static_cast <IntType> (r.nextInt64 ());
}
template <class IntType>
void testInteger (IntType in)
{
std::string s;
IntType out (in+1);
expect (lexicalCastChecked (s, in));
expect (lexicalCastChecked (out, s));
expect (out == in);
}
template <class IntType>
void testIntegers (Random& r)
{
{
std::stringstream ss;
ss <<
"random " << typeid (IntType).name ();
testcase (ss.str());
for (int i = 0; i < 1000; ++i)
{
IntType const value (nextRandomInt <IntType> (r));
testInteger (value);
}
}
{
std::stringstream ss;
ss <<
"numeric_limits <" << typeid (IntType).name () << ">";
testcase (ss.str());
testInteger (std::numeric_limits <IntType>::min ());
testInteger (std::numeric_limits <IntType>::max ());
}
}
void testPathologies()
{
testcase("pathologies");
try
{
lexicalCastThrow<int>("\xef\xbc\x91\xef\xbc\x90"); // utf-8 encoded
fail("Should throw");
}
catch(BadLexicalCast const&)
{
pass();
}
}
void run()
{
std::int64_t const seedValue = 50;
Random r (seedValue);
testIntegers <int> (r);
testIntegers <unsigned int> (r);
testIntegers <short> (r);
testIntegers <unsigned short> (r);
testIntegers <std::int32_t> (r);
testIntegers <std::uint32_t> (r);
testIntegers <std::int64_t> (r);
testIntegers <std::uint64_t> (r);
testPathologies();
}
};
BEAST_DEFINE_TESTSUITE(LexicalCast,beast_core,beast);
} // beast

View File

@@ -0,0 +1,242 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_LEXICALCAST_H_INCLUDED
#define BEAST_LEXICALCAST_H_INCLUDED
#include <string>
#include <beast/cxx14/type_traits.h> // <type_traits>
#include <cerrno>
#include <cstdlib>
#include <limits>
#include <utility>
namespace beast {
namespace detail {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4800)
#pragma warning(disable: 4804)
#endif
template <class IntType>
bool
parseSigned (IntType& result, char const* begin, char const* end)
{
static_assert(std::is_signed<IntType>::value, "");
char* ptr;
auto errno_save = errno;
errno = 0;
long long r = std::strtoll(begin, &ptr, 10);
std::swap(errno, errno_save);
errno_save = ptr != end;
if (errno_save == 0)
{
if (std::numeric_limits<IntType>::min() <= r &&
r <= std::numeric_limits<IntType>::max())
result = static_cast<IntType>(r);
else
errno_save = 1;
}
return errno_save == 0;
}
template <class UIntType>
bool
parseUnsigned (UIntType& result, char const* begin, char const* end)
{
static_assert(std::is_unsigned<UIntType>::value, "");
char* ptr;
auto errno_save = errno;
errno = 0;
unsigned long long r = std::strtoull(begin, &ptr, 10);
std::swap(errno, errno_save);
errno_save = ptr != end;
if (errno_save == 0)
{
if (r <= std::numeric_limits<UIntType>::max())
result = static_cast<UIntType>(r);
else
errno_save = 1;
}
return errno_save == 0;
}
//------------------------------------------------------------------------------
// These specializatons get called by the non-member functions to do the work
template <class Out, class In>
struct LexicalCast;
// conversion to std::string
template <class In>
struct LexicalCast <std::string, In>
{
bool operator() (std::string& out, short in) { out = std::to_string(in); return true; }
bool operator() (std::string& out, int in) { out = std::to_string(in); return true; }
bool operator() (std::string& out, long in) { out = std::to_string(in); return true; }
bool operator() (std::string& out, long long in) { out = std::to_string(in); return true; }
bool operator() (std::string& out, unsigned short in) { out = std::to_string(in); return true; }
bool operator() (std::string& out, unsigned int in) { out = std::to_string(in); return true; }
bool operator() (std::string& out, unsigned long in) { out = std::to_string(in); return true; }
bool operator() (std::string& out, unsigned long long in) { out = std::to_string(in); return true; }
bool operator() (std::string& out, float in) { out = std::to_string(in); return true; }
bool operator() (std::string& out, double in) { out = std::to_string(in); return true; }
bool operator() (std::string& out, long double in) { out = std::to_string(in); return true; }
};
// Parse std::string to number
template <class Out>
struct LexicalCast <Out, std::string>
{
bool operator() (short& out, std::string const& in) const { return parseSigned (out, in.data(), in.data()+in.size()); }
bool operator() (int& out, std::string const& in) const { return parseSigned (out, in.data(), in.data()+in.size()); }
bool operator() (long& out, std::string const& in) const { return parseSigned (out, in.data(), in.data()+in.size()); }
bool operator() (long long& out, std::string const& in) const { return parseSigned (out, in.data(), in.data()+in.size()); }
bool operator() (unsigned short& out, std::string const& in) const { return parseUnsigned (out, in.data(), in.data()+in.size()); }
bool operator() (unsigned int& out, std::string const& in) const { return parseUnsigned (out, in.data(), in.data()+in.size()); }
bool operator() (unsigned long& out, std::string const& in) const { return parseUnsigned (out, in.data(), in.data()+in.size()); }
bool operator() (unsigned long long& out, std::string const& in) const { return parseUnsigned (out, in.data(), in.data()+in.size()); }
bool operator() (float& out, std::string const& in) const { bassertfalse; return false; /* UNIMPLEMENTED! */ }
bool operator() (double& out, std::string const& in) const { bassertfalse; return false; /* UNIMPLEMENTED! */ }
bool operator() (long double& out, std::string const& in) const { bassertfalse; return false; /* UNIMPLEMENTED! */ }
#if 0
bool operator() (bool& out, std::string const& in) const;
#else
bool operator() (bool& out, std::string const& in) const { return parseUnsigned (out, in.data(), in.data()+in.size()); }
#endif
};
#if 0
template <class Out>
bool
LexicalCast <Out, std::string>::operator() (bool& out, std::string const& in) const
{
// boost::lexical_cast is very strict, it
// throws on anything but "1" or "0"
//
if (in == "1")
{
out = true;
return true;
}
else if (in == "0")
{
out = false;
return true;
}
return false;
}
#endif
//------------------------------------------------------------------------------
// Conversion from null terminated char const*
template <class Out>
struct LexicalCast <Out, char const*>
{
bool operator() (Out& out, char const* in) const
{
return LexicalCast <Out, std::string>()(out, in);
}
};
// Conversion from null terminated char*
// The string is not modified.
template <class Out>
struct LexicalCast <Out, char*>
{
bool operator() (Out& out, char* in) const
{
Out result;
if (LexicalCast <Out, char const*> () (result, in))
{
out = result;
return true;
}
return false;
}
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif
} // detail
//------------------------------------------------------------------------------
/** Thrown when a conversion is not possible with LexicalCast.
Only used in the throw variants of lexicalCast.
*/
struct BadLexicalCast : public std::bad_cast
{
};
/** Intelligently convert from one type to another.
@return `false` if there was a parsing or range error
*/
template <class Out, class In>
bool lexicalCastChecked (Out& out, In in)
{
return detail::LexicalCast <Out, In> () (out, in);
}
/** Convert from one type to another, throw on error
An exception of type BadLexicalCast is thrown if the conversion fails.
@return The new type.
*/
template <class Out, class In>
Out lexicalCastThrow (In in)
{
Out out;
if (lexicalCastChecked (out, in))
return out;
throw BadLexicalCast ();
}
/** Convert from one type to another.
@param defaultValue The value returned if parsing fails
@return The new type.
*/
template <class Out, class In>
Out lexicalCast (In in, Out defaultValue = Out ())
{
Out out;
if (lexicalCastChecked (out, in))
return out;
return defaultValue;
}
} // beast
#endif

View File

@@ -0,0 +1,515 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
StringArray::StringArray() noexcept
{
}
StringArray::StringArray (const StringArray& other)
: strings (other.strings)
{
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
StringArray::StringArray (StringArray&& other) noexcept
: strings (static_cast <Array <String>&&> (other.strings))
{
}
#endif
StringArray::StringArray (const String& firstValue)
{
strings.add (firstValue);
}
namespace StringArrayHelpers
{
template <typename CharType>
void addArray (Array<String>& dest, const CharType* const* strings)
{
if (strings != nullptr)
while (*strings != nullptr)
dest.add (*strings++);
}
template <typename Type>
void addArray (Array<String>& dest, const Type* const strings, const int numberOfStrings)
{
for (int i = 0; i < numberOfStrings; ++i)
dest.add (strings [i]);
}
}
StringArray::StringArray (const String* initialStrings, int numberOfStrings)
{
StringArrayHelpers::addArray (strings, initialStrings, numberOfStrings);
}
StringArray::StringArray (const char* const* const initialStrings)
{
StringArrayHelpers::addArray (strings, initialStrings);
}
StringArray::StringArray (const char* const* const initialStrings, const int numberOfStrings)
{
StringArrayHelpers::addArray (strings, initialStrings, numberOfStrings);
}
StringArray::StringArray (const wchar_t* const* const initialStrings)
{
StringArrayHelpers::addArray (strings, initialStrings);
}
StringArray::StringArray (const wchar_t* const* const initialStrings, const int numberOfStrings)
{
StringArrayHelpers::addArray (strings, initialStrings, numberOfStrings);
}
StringArray& StringArray::operator= (const StringArray& other)
{
strings = other.strings;
return *this;
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
StringArray& StringArray::operator= (StringArray&& other) noexcept
{
strings = static_cast <Array<String>&&> (other.strings);
return *this;
}
#endif
StringArray::~StringArray()
{
}
bool StringArray::operator== (const StringArray& other) const noexcept
{
if (other.size() != size())
return false;
for (int i = size(); --i >= 0;)
if (other.strings.getReference(i) != strings.getReference(i))
return false;
return true;
}
bool StringArray::operator!= (const StringArray& other) const noexcept
{
return ! operator== (other);
}
void StringArray::swapWith (StringArray& other) noexcept
{
strings.swapWith (other.strings);
}
void StringArray::clear()
{
strings.clear();
}
const String& StringArray::operator[] (const int index) const noexcept
{
if (isPositiveAndBelow (index, strings.size()))
return strings.getReference (index);
return String::empty;
}
String& StringArray::getReference (const int index) noexcept
{
bassert (isPositiveAndBelow (index, strings.size()));
return strings.getReference (index);
}
void StringArray::add (const String& newString)
{
strings.add (newString);
}
void StringArray::insert (const int index, const String& newString)
{
strings.insert (index, newString);
}
void StringArray::addIfNotAlreadyThere (const String& newString, const bool ignoreCase)
{
if (! contains (newString, ignoreCase))
add (newString);
}
void StringArray::addArray (const StringArray& otherArray, int startIndex, int numElementsToAdd)
{
if (startIndex < 0)
{
bassertfalse;
startIndex = 0;
}
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > otherArray.size())
numElementsToAdd = otherArray.size() - startIndex;
while (--numElementsToAdd >= 0)
strings.add (otherArray.strings.getReference (startIndex++));
}
void StringArray::set (const int index, const String& newString)
{
strings.set (index, newString);
}
bool StringArray::contains (const String& stringToLookFor, const bool ignoreCase) const
{
if (ignoreCase)
{
for (int i = size(); --i >= 0;)
if (strings.getReference(i).equalsIgnoreCase (stringToLookFor))
return true;
}
else
{
for (int i = size(); --i >= 0;)
if (stringToLookFor == strings.getReference(i))
return true;
}
return false;
}
int StringArray::indexOf (const String& stringToLookFor, const bool ignoreCase, int i) const
{
if (i < 0)
i = 0;
const int numElements = size();
if (ignoreCase)
{
while (i < numElements)
{
if (strings.getReference(i).equalsIgnoreCase (stringToLookFor))
return i;
++i;
}
}
else
{
while (i < numElements)
{
if (stringToLookFor == strings.getReference (i))
return i;
++i;
}
}
return -1;
}
//==============================================================================
void StringArray::remove (const int index)
{
strings.remove (index);
}
void StringArray::removeString (const String& stringToRemove,
const bool ignoreCase)
{
if (ignoreCase)
{
for (int i = size(); --i >= 0;)
if (strings.getReference(i).equalsIgnoreCase (stringToRemove))
strings.remove (i);
}
else
{
for (int i = size(); --i >= 0;)
if (stringToRemove == strings.getReference (i))
strings.remove (i);
}
}
void StringArray::removeRange (int startIndex, int numberToRemove)
{
strings.removeRange (startIndex, numberToRemove);
}
//==============================================================================
void StringArray::removeEmptyStrings (const bool removeWhitespaceStrings)
{
if (removeWhitespaceStrings)
{
for (int i = size(); --i >= 0;)
if (! strings.getReference(i).containsNonWhitespaceChars())
strings.remove (i);
}
else
{
for (int i = size(); --i >= 0;)
if (strings.getReference(i).isEmpty())
strings.remove (i);
}
}
void StringArray::trim()
{
for (int i = size(); --i >= 0;)
{
String& s = strings.getReference(i);
s = s.trim();
}
}
//==============================================================================
struct InternalStringArrayComparator_CaseSensitive
{
static int compareElements (String& first, String& second) { return first.compare (second); }
};
struct InternalStringArrayComparator_CaseInsensitive
{
static int compareElements (String& first, String& second) { return first.compareIgnoreCase (second); }
};
void StringArray::sort (const bool ignoreCase)
{
if (ignoreCase)
{
InternalStringArrayComparator_CaseInsensitive comp;
strings.sort (comp);
}
else
{
InternalStringArrayComparator_CaseSensitive comp;
strings.sort (comp);
}
}
void StringArray::move (const int currentIndex, int newIndex) noexcept
{
strings.move (currentIndex, newIndex);
}
//==============================================================================
String StringArray::joinIntoString (const String& separator, int start, int numberToJoin) const
{
const int last = (numberToJoin < 0) ? size()
: bmin (size(), start + numberToJoin);
if (start < 0)
start = 0;
if (start >= last)
return String::empty;
if (start == last - 1)
return strings.getReference (start);
const size_t separatorBytes = separator.getCharPointer().sizeInBytes() - sizeof (String::CharPointerType::CharType);
size_t bytesNeeded = separatorBytes * (size_t) (last - start - 1);
for (int i = start; i < last; ++i)
bytesNeeded += strings.getReference(i).getCharPointer().sizeInBytes() - sizeof (String::CharPointerType::CharType);
String result;
result.preallocateBytes (bytesNeeded);
String::CharPointerType dest (result.getCharPointer());
while (start < last)
{
const String& s = strings.getReference (start);
if (! s.isEmpty())
dest.writeAll (s.getCharPointer());
if (++start < last && separatorBytes > 0)
dest.writeAll (separator.getCharPointer());
}
dest.writeNull();
return result;
}
int StringArray::addTokens (const String& text, const bool preserveQuotedStrings)
{
return addTokens (text, " \n\r\t", preserveQuotedStrings ? "\"" : "");
}
int StringArray::addTokens (const String& text, const String& breakCharacters, const String& quoteCharacters)
{
int num = 0;
String::CharPointerType t (text.getCharPointer());
if (! t.isEmpty())
{
for (;;)
{
String::CharPointerType tokenEnd (CharacterFunctions::findEndOfToken (t,
breakCharacters.getCharPointer(),
quoteCharacters.getCharPointer()));
strings.add (String (t, tokenEnd));
++num;
if (tokenEnd.isEmpty())
break;
t = ++tokenEnd;
}
}
return num;
}
int StringArray::addLines (const String& sourceText)
{
int numLines = 0;
String::CharPointerType text (sourceText.getCharPointer());
bool finished = text.isEmpty();
while (! finished)
{
for (String::CharPointerType startOfLine (text);;)
{
const String::CharPointerType endOfLine (text);
switch (text.getAndAdvance())
{
case 0: finished = true; break;
case '\n': break;
case '\r': if (*text == '\n') ++text; break;
default: continue;
}
strings.add (String (startOfLine, endOfLine));
++numLines;
break;
}
}
return numLines;
}
StringArray StringArray::fromTokens (const String& stringToTokenise,
bool preserveQuotedStrings)
{
StringArray s;
s.addTokens (stringToTokenise, preserveQuotedStrings);
return s;
}
StringArray StringArray::fromTokens (const String& stringToTokenise,
const String& breakCharacters,
const String& quoteCharacters)
{
StringArray s;
s.addTokens (stringToTokenise, breakCharacters, quoteCharacters);
return s;
}
StringArray StringArray::fromLines (const String& stringToBreakUp)
{
StringArray s;
s.addLines (stringToBreakUp);
return s;
}
//==============================================================================
void StringArray::removeDuplicates (const bool ignoreCase)
{
for (int i = 0; i < size() - 1; ++i)
{
const String s (strings.getReference(i));
int nextIndex = i + 1;
for (;;)
{
nextIndex = indexOf (s, ignoreCase, nextIndex);
if (nextIndex < 0)
break;
strings.remove (nextIndex);
}
}
}
void StringArray::appendNumbersToDuplicates (const bool ignoreCase,
const bool appendNumberToFirstInstance,
CharPointer_UTF8 preNumberString,
CharPointer_UTF8 postNumberString)
{
CharPointer_UTF8 defaultPre (" ("), defaultPost (")");
if (preNumberString.getAddress() == nullptr)
preNumberString = defaultPre;
if (postNumberString.getAddress() == nullptr)
postNumberString = defaultPost;
for (int i = 0; i < size() - 1; ++i)
{
String& s = strings.getReference(i);
int nextIndex = indexOf (s, ignoreCase, i + 1);
if (nextIndex >= 0)
{
const String original (s);
int number = 0;
if (appendNumberToFirstInstance)
s = original + String (preNumberString) + String (++number) + String (postNumberString);
else
++number;
while (nextIndex >= 0)
{
set (nextIndex, (*this)[nextIndex] + String (preNumberString) + String (++number) + String (postNumberString));
nextIndex = indexOf (original, ignoreCase, nextIndex + 1);
}
}
}
}
void StringArray::ensureStorageAllocated (int minNumElements)
{
strings.ensureStorageAllocated (minNumElements);
}
void StringArray::minimiseStorageOverheads()
{
strings.minimiseStorageOverheads();
}
} // beast

View File

@@ -0,0 +1,414 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_STRINGARRAY_H_INCLUDED
#define BEAST_STRINGARRAY_H_INCLUDED
#include <beast/module/core/containers/Array.h>
#include <beast/module/core/threads/CriticalSection.h>
namespace beast {
//==============================================================================
/**
A special array for holding a list of strings.
@see String, StringPairArray
*/
class StringArray
{
public:
//==============================================================================
/** Creates an empty string array */
StringArray() noexcept;
/** Creates a copy of another string array */
StringArray (const StringArray& other);
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
StringArray (StringArray&& other) noexcept;
#endif
/** Creates an array containing a single string. */
explicit StringArray (const String& firstValue);
/** 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& other);
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
StringArray& operator= (StringArray&& other) noexcept;
#endif
/** Swaps the contents of this and another StringArray. */
void swapWith (StringArray& other) 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& other) 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& other) const noexcept;
//==============================================================================
/** Returns the number of strings in the array */
inline int size() const noexcept { return strings.size(); };
/** 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 pointer to the first String in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline 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() 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 (const String& 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 (const String& stringToLookFor,
bool ignoreCase = false,
int startIndex = 0) const;
//==============================================================================
/** Appends a string at the end of the array. */
void add (const 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, const String& stringToAdd);
/** Adds a string to the array as long as it's not already in there.
The search can optionally be case-insensitive.
*/
void 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, const 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);
/** 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 (const String& 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 (const String& stringToTokenise,
const String& breakCharacters,
const String& 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 (const String& 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 these tokens as an array.
@see addTokens
*/
static StringArray fromTokens (const String& stringToTokenise,
bool preserveQuotedStrings);
/** 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 these 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 (const String& stringToTokenise,
const String& breakCharacters,
const String& 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 (const String& stringToBreakUp);
//==============================================================================
/** Removes all elements from the array. */
void clear();
/** 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 the first occurrence of the given string from the array. The
comparison may be case-insensitive depending on the ignoreCase parameter.
*/
void removeString (const String& 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 0, 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 0, 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 (const String& separatorString,
int startIndex = 0,
int numberOfElements = -1) const;
//==============================================================================
/** Sorts the array into alphabetical order.
@param ignoreCase if true, the comparisons used will be case-sensitive.
*/
void sort (bool ignoreCase);
//==============================================================================
/** 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();
private:
Array <String> strings;
};
} // beast
#endif // BEAST_STRINGARRAY_H_INCLUDED

View File

@@ -0,0 +1,149 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
StringPairArray::StringPairArray (const bool ignoreCase_)
: ignoreCase (ignoreCase_)
{
}
StringPairArray::StringPairArray (const StringPairArray& other)
: keys (other.keys),
values (other.values),
ignoreCase (other.ignoreCase)
{
}
StringPairArray::~StringPairArray()
{
}
StringPairArray& StringPairArray::operator= (const StringPairArray& other)
{
keys = other.keys;
values = other.values;
return *this;
}
void StringPairArray::swapWith (StringPairArray& other)
{
std::swap (ignoreCase, other.ignoreCase);
keys.swapWith (other.keys);
values.swapWith (other.values);
}
bool StringPairArray::operator== (const StringPairArray& other) const
{
for (int i = keys.size(); --i >= 0;)
if (other [keys[i]] != values[i])
return false;
return true;
}
bool StringPairArray::operator!= (const StringPairArray& other) const
{
return ! operator== (other);
}
const String& StringPairArray::operator[] (const String& key) const
{
return values [keys.indexOf (key, ignoreCase)];
}
String StringPairArray::getValue (const String& key, const String& defaultReturnValue) const
{
const int i = keys.indexOf (key, ignoreCase);
if (i >= 0)
return values[i];
return defaultReturnValue;
}
void StringPairArray::set (const String& key, const String& value)
{
const int i = keys.indexOf (key, ignoreCase);
if (i >= 0)
{
values.set (i, value);
}
else
{
keys.add (key);
values.add (value);
}
}
void StringPairArray::addArray (const StringPairArray& other)
{
for (int i = 0; i < other.size(); ++i)
set (other.keys[i], other.values[i]);
}
void StringPairArray::clear()
{
keys.clear();
values.clear();
}
void StringPairArray::remove (const String& key)
{
remove (keys.indexOf (key, ignoreCase));
}
void StringPairArray::remove (const int index)
{
keys.remove (index);
values.remove (index);
}
void StringPairArray::setIgnoresCase (const bool shouldIgnoreCase)
{
ignoreCase = shouldIgnoreCase;
}
String StringPairArray::getDescription() const
{
String s;
for (int i = 0; i < keys.size(); ++i)
{
s << keys[i] << " = " << values[i];
if (i < keys.size())
s << ", ";
}
return s;
}
void StringPairArray::minimiseStorageOverheads()
{
keys.minimiseStorageOverheads();
values.minimiseStorageOverheads();
}
} // beast

View File

@@ -0,0 +1,162 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_STRINGPAIRARRAY_H_INCLUDED
#define BEAST_STRINGPAIRARRAY_H_INCLUDED
#include <beast/module/core/text/StringArray.h>
#include <beast/utility/LeakChecked.h>
namespace beast {
//==============================================================================
/**
A container for holding a set of strings which are keyed by another string.
@see StringArray
*/
class StringPairArray : LeakChecked <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);
/** Swap the contents of this array with another. */
void swapWith (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[] (const String& 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 (const String& key, const String& defaultReturnValue) const;
/** 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 (const String& 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);
//==============================================================================
/** 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();
private:
//==============================================================================
StringArray keys, values;
bool ignoreCase;
};
} // beast
#endif // BEAST_STRINGPAIRARRAY_H_INCLUDED

View File

@@ -0,0 +1,248 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
class DeadlineTimer::Manager
: public LeakChecked <Manager>
, protected Thread
{
private:
typedef CriticalSection LockType;
typedef List <DeadlineTimer> Items;
public:
Manager () : Thread ("DeadlineTimer::Manager")
{
startThread ();
}
~Manager ()
{
signalThreadShouldExit ();
notify ();
waitForThreadToExit ();
bassert (m_items.empty ());
}
// Okay to call on an active timer.
// However, an extra notification may still happen due to concurrency.
//
void activate (DeadlineTimer& timer,
double secondsRecurring, RelativeTime const& when)
{
bassert (secondsRecurring >= 0);
std::lock_guard <LockType> lock (m_mutex);
if (timer.m_isActive)
{
m_items.erase (m_items.iterator_to (timer));
timer.m_isActive = false;
}
timer.m_secondsRecurring = secondsRecurring;
timer.m_notificationTime = when;
insertSorted (timer);
timer.m_isActive = true;
notify ();
}
// Okay to call this on an inactive timer.
// This can happen naturally based on concurrency.
//
void deactivate (DeadlineTimer& timer)
{
std::lock_guard <LockType> lock (m_mutex);
if (timer.m_isActive)
{
m_items.erase (m_items.iterator_to (timer));
timer.m_isActive = false;
notify ();
}
}
void run ()
{
while (! threadShouldExit ())
{
RelativeTime const currentTime (
RelativeTime::fromStartup ());
double seconds (0);
DeadlineTimer* timer (nullptr);
{
std::lock_guard <LockType> lock (m_mutex);
// See if a timer expired
if (! m_items.empty ())
{
timer = &m_items.front ();
// Has this timer expired?
if (timer->m_notificationTime <= currentTime)
{
// Expired, remove it from the list.
bassert (timer->m_isActive);
m_items.pop_front ();
// Is the timer recurring?
if (timer->m_secondsRecurring > 0)
{
// Yes so set the timer again.
timer->m_notificationTime =
currentTime + timer->m_secondsRecurring;
// Put it back into the list as active
insertSorted (*timer);
}
else
{
// Not a recurring timer, deactivate it.
timer->m_isActive = false;
}
timer->m_listener->onDeadlineTimer (*timer);
// re-loop
seconds = -1;
}
else
{
seconds = (
timer->m_notificationTime - currentTime).inSeconds ();
// Can't be zero and come into the else clause.
bassert (seconds != 0);
// Don't call the listener
timer = nullptr;
}
}
}
// Note that we have released the lock here.
if (seconds > 0)
{
// Wait until interrupt or next timer.
//
int const milliSeconds (std::max (
static_cast <int> (seconds * 1000 + 0.5), 1));
bassert (milliSeconds > 0);
wait (milliSeconds);
}
else if (seconds == 0)
{
// Wait until interrupt
//
wait ();
}
else
{
// Do not wait. This can happen if the recurring timer duration
// is extremely short, or if a listener wastes too much time in
// their callback.
}
}
}
// Caller is responsible for locking
void insertSorted (DeadlineTimer& timer)
{
if (! m_items.empty ())
{
Items::iterator before = m_items.begin ();
for (;;)
{
if (before->m_notificationTime >= timer.m_notificationTime)
{
m_items.insert (before, timer);
break;
}
++before;
if (before == m_items.end ())
{
m_items.push_back (timer);
break;
}
}
}
else
{
m_items.push_back (timer);
}
}
private:
CriticalSection m_mutex;
Items m_items;
};
//------------------------------------------------------------------------------
DeadlineTimer::DeadlineTimer (Listener* listener)
: m_listener (listener)
, m_manager (SharedSingleton <Manager>::getInstance ())
, m_isActive (false)
{
}
DeadlineTimer::~DeadlineTimer ()
{
m_manager->deactivate (*this);
}
void DeadlineTimer::cancel ()
{
m_manager->deactivate (*this);
}
void DeadlineTimer::setExpiration (double secondsUntilDeadline)
{
bassert (secondsUntilDeadline != 0);
RelativeTime const when (
RelativeTime::fromStartup() + secondsUntilDeadline);
m_manager->activate (*this, 0, when);
}
void DeadlineTimer::setRecurringExpiration (double secondsUntilDeadline)
{
bassert (secondsUntilDeadline != 0);
RelativeTime const when (
RelativeTime::fromStartup() + secondsUntilDeadline);
m_manager->activate (*this, secondsUntilDeadline, when);
}
} // beast

View File

@@ -0,0 +1,116 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_DEADLINETIMER_H_INCLUDED
#define BEAST_DEADLINETIMER_H_INCLUDED
namespace beast
{
/** Provides periodic or one time notifications at a specified time interval.
*/
class DeadlineTimer
: public List <DeadlineTimer>::Node
, public Uncopyable
{
public:
/** Listener for a deadline timer.
The listener is called on an auxiliary thread. It is suggested
not to perform any time consuming operations during the call.
*/
// VFALCO TODO Perhaps allow construction using a ServiceQueue to use
// for notifications.
//
class Listener
{
public:
virtual void onDeadlineTimer (DeadlineTimer&) { }
};
public:
/** Create a deadline timer with the specified listener attached.
*/
explicit DeadlineTimer (Listener* listener);
~DeadlineTimer ();
/** Cancel all notifications.
It is okay to call this on an inactive timer.
@note It is guaranteed that no notifications will occur after this
function returns.
*/
void cancel ();
/** Set the timer to go off once in the future.
If the timer is already active, this will reset it.
@note If the timer is already active, the old one might go off
before this function returns.
@param secondsUntilDeadline The number of seconds until the timer
will send a notification. This must be
greater than zero.
*/
/** @{ */
void setExpiration (double secondsUntilDeadline);
template <class Rep, class Period>
void setExpiration (std::chrono::duration <Rep, Period> const& amount)
{
setExpiration (std::chrono::duration_cast <
std::chrono::duration <double>> (amount).count ());
}
/** @} */
/** Set the timer to go off repeatedly with the specified frequency.
If the timer is already active, this will reset it.
@note If the timer is already active, the old one might go off
before this function returns.
@param secondsUntilDeadline The number of seconds until the timer
will send a notification. This must be
greater than zero.
*/
void setRecurringExpiration (double secondsUntilDeadline);
/** Equality comparison.
Timers are equal if they have the same address.
*/
inline bool operator== (DeadlineTimer const& other) const
{
return this == &other;
}
/** Inequality comparison. */
inline bool operator!= (DeadlineTimer const& other) const
{
return this != &other;
}
private:
class Manager;
Listener* const m_listener;
SharedPtr <SharedSingleton <Manager> > m_manager;
bool m_isActive;
RelativeTime m_notificationTime;
double m_secondsRecurring; // non zero if recurring
};
} // beast
#endif

View File

@@ -0,0 +1,80 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CORE_THREAD_MUTEXTRAITS_H_INCLUDED
#define BEAST_CORE_THREAD_MUTEXTRAITS_H_INCLUDED
namespace beast
{
/** Adapt a Mutex type to meet the boost::Mutex concept requirements.
The default implementation assumes adherance to the boost::Mutex concepts,
with one important exception. We make the member functions const, for
convenience.
*/
template <typename Mutex>
struct MutexTraits
{
// BasicLockable
// http://www.boost.org/doc/libs/1_54_0/doc/html/thread/synchronization.html#thread.synchronization.mutex_concepts.basic_lockable
//
static inline void lock (Mutex const& mutex) noexcept
{
(const_cast <Mutex&> (mutex)).lock ();
}
static inline void unlock (Mutex const& mutex) noexcept
{
(const_cast <Mutex&> (mutex)).unlock ();
}
// Lockable
// http://www.boost.org/doc/libs/1_54_0/doc/html/thread/synchronization.html#thread.synchronization.mutex_concepts.basic_lockable
//
static inline bool try_lock (Mutex const& mutex) noexcept
{
return (const_cast <Mutex&> (mutex)).try_lock ();
}
};
//------------------------------------------------------------------------------
/** MutexTraits Specialization for a beast CriticalSection. */
template <>
struct MutexTraits <CriticalSection>
{
static inline void lock (CriticalSection const& mutex) noexcept
{
mutex.lock ();
}
static inline void unlock (CriticalSection const& mutex) noexcept
{
mutex.unlock ();
}
static inline bool try_lock (CriticalSection const& mutex) noexcept
{
return mutex.try_lock ();
}
};
} // beast
#endif

View File

@@ -0,0 +1,299 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
namespace beast {
Workers::Workers (Callback& callback, String const& threadNames, int numberOfThreads)
: m_callback (callback)
, m_threadNames (threadNames)
, m_allPaused (true, true)
, m_semaphore (0)
, m_numberOfThreads (0)
{
setNumberOfThreads (numberOfThreads);
}
Workers::~Workers ()
{
pauseAllThreadsAndWait ();
deleteWorkers (m_everyone);
}
int Workers::getNumberOfThreads () const noexcept
{
return m_numberOfThreads;
}
// VFALCO NOTE if this function is called quickly to reduce then
// increase the number of threads, it could result in
// more paused threads being created than expected.
//
void Workers::setNumberOfThreads (int numberOfThreads)
{
if (m_numberOfThreads != numberOfThreads)
{
if (numberOfThreads > m_numberOfThreads)
{
// Increasing the number of working threads
int const amount = numberOfThreads - m_numberOfThreads;
for (int i = 0; i < amount; ++i)
{
// See if we can reuse a paused worker
Worker* worker = m_paused.pop_front ();
if (worker != nullptr)
{
// If we got here then the worker thread is at [1]
// This will unblock their call to wait()
//
worker->notify ();
}
else
{
worker = new Worker (*this, m_threadNames);
}
m_everyone.push_front (worker);
}
}
else if (numberOfThreads < m_numberOfThreads)
{
// Decreasing the number of working threads
int const amount = m_numberOfThreads - numberOfThreads;
for (int i = 0; i < amount; ++i)
{
++m_pauseCount;
// Pausing a thread counts as one "internal task"
m_semaphore.signal ();
}
}
m_numberOfThreads = numberOfThreads;
}
}
void Workers::pauseAllThreadsAndWait ()
{
setNumberOfThreads (0);
m_allPaused.wait ();
bassert (numberOfCurrentlyRunningTasks () == 0);
}
void Workers::addTask ()
{
m_semaphore.signal ();
}
int Workers::numberOfCurrentlyRunningTasks () const noexcept
{
return m_runningTaskCount.get ();
}
void Workers::deleteWorkers (LockFreeStack <Worker>& stack)
{
for (;;)
{
Worker* const worker = stack.pop_front ();
if (worker != nullptr)
{
// This call blocks until the thread orderly exits
delete worker;
}
else
{
break;
}
}
}
//------------------------------------------------------------------------------
Workers::Worker::Worker (Workers& workers, String const& threadName)
: Thread (threadName)
, m_workers (workers)
{
startThread ();
}
Workers::Worker::~Worker ()
{
stopThread ();
}
void Workers::Worker::run ()
{
while (! threadShouldExit ())
{
// Increment the count of active workers, and if
// we are the first one then reset the "all paused" event
//
if (++m_workers.m_activeCount == 1)
m_workers.m_allPaused.reset ();
for (;;)
{
// Acquire a task or "internal task."
//
m_workers.m_semaphore.wait ();
// See if there's a pause request. This
// counts as an "internal task."
//
int pauseCount = m_workers.m_pauseCount.get ();
if (pauseCount > 0)
{
// Try to decrement
pauseCount = --m_workers.m_pauseCount;
if (pauseCount >= 0)
{
// We got paused
break;
}
else
{
// Undo our decrement
++m_workers.m_pauseCount;
}
}
// We couldn't pause so we must have gotten
// unblocked in order to process a task.
//
++m_workers.m_runningTaskCount;
m_workers.m_callback.processTask ();
--m_workers.m_runningTaskCount;
// Put the name back in case the callback changed it
Thread::setCurrentThreadName (Thread::getThreadName());
}
// Any worker that goes into the paused list must
// guarantee that it will eventually block on its
// event object.
//
m_workers.m_paused.push_front (this);
// Decrement the count of active workers, and if we
// are the last one then signal the "all paused" event.
//
if (--m_workers.m_activeCount == 0)
m_workers.m_allPaused.signal ();
Thread::setCurrentThreadName ("(" + getThreadName() + ")");
// [1] We will be here when the paused list is popped
//
// We block on our event object, a requirement of being
// put into the paused list.
//
// This will get signaled on either a reactivate or a stopThread()
//
wait ();
}
}
//------------------------------------------------------------------------------
class Workers_test : public unit_test::suite
{
public:
struct TestCallback : Workers::Callback
{
explicit TestCallback (int count_)
: finished (false, count_ == 0)
, count (count_)
{
}
void processTask ()
{
if (--count == 0)
finished.signal ();
}
WaitableEvent finished;
Atomic <int> count;
};
template <class T1, class T2>
bool
expectEquals (T1 const& t1, T2 const& t2)
{
return expect (t1 == t2);
}
void testThreads (int const threadCount)
{
std::stringstream ss;
ss <<
"threadCount = " << threadCount;
testcase (ss.str());
TestCallback cb (threadCount);
Workers w (cb, "Test", 0);
expect (w.getNumberOfThreads () == 0);
w.setNumberOfThreads (threadCount);
expect (w.getNumberOfThreads () == threadCount);
for (int i = 0; i < threadCount; ++i)
w.addTask ();
// 10 seconds should be enough to finish on any system
//
bool signaled = cb.finished.wait (10 * 1000);
expect (signaled, "timed out");
w.pauseAllThreadsAndWait ();
int const count (cb.count.get ());
expectEquals (count, 0);
}
void run ()
{
testThreads (0);
testThreads (1);
testThreads (2);
testThreads (4);
testThreads (16);
testThreads (64);
}
};
BEAST_DEFINE_TESTSUITE(Workers,beast_core,beast);
} // beast

View File

@@ -0,0 +1,149 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_WORKERS_H_INCLUDED
#define BEAST_WORKERS_H_INCLUDED
#include <beast/module/core/system/SystemStats.h>
#include <beast/threads/semaphore.h>
namespace beast {
/** A group of threads that process tasks.
*/
class Workers
{
public:
/** Called to perform tasks as needed. */
struct Callback
{
/** Perform a task.
The call is made on a thread owned by Workers. It is important
that you only process one task from inside your callback. Each
call to addTask will result in exactly one call to processTask.
@see Workers::addTask
*/
virtual void processTask () = 0;
};
/** Create the object.
A number of initial threads may be optionally specified. The
default is to create one thread per CPU.
@param threadNames The name given to each created worker thread.
*/
explicit Workers (Callback& callback,
String const& threadNames = "Worker",
int numberOfThreads = SystemStats::getNumCpus ());
~Workers ();
/** Retrieve the desired number of threads.
This just returns the number of active threads that were requested. If
there was a recent call to setNumberOfThreads, the actual number of active
threads may be temporarily different from what was last requested.
@note This function is not thread-safe.
*/
int getNumberOfThreads () const noexcept;
/** Set the desired number of threads.
@note This function is not thread-safe.
*/
void setNumberOfThreads (int numberOfThreads);
/** Pause all threads and wait until they are paused.
If a thread is processing a task it will pause as soon as the task
completes. There may still be tasks signaled even after all threads
have paused.
@note This function is not thread-safe.
*/
void pauseAllThreadsAndWait ();
/** Add a task to be performed.
Every call to addTask will eventually result in a call to
Callback::processTask unless the Workers object is destroyed or
the number of threads is never set above zero.
@note This function is thread-safe.
*/
void addTask ();
/** Get the number of currently executing calls of Callback::processTask.
While this function is thread-safe, the value may not stay
accurate for very long. It's mainly for diagnostic purposes.
*/
int numberOfCurrentlyRunningTasks () const noexcept;
//--------------------------------------------------------------------------
private:
struct PausedTag { };
/* A Worker executes tasks on its provided thread.
These are the states:
Active: Running the task processing loop.
Idle: Active, but blocked on waiting for a task.
Pausd: Blocked waiting to exit or become active.
*/
class Worker
: public LockFreeStack <Worker>::Node
, public LockFreeStack <Worker, PausedTag>::Node
, public Thread
{
public:
Worker (Workers& workers, String const& threadName);
~Worker ();
private:
void run ();
private:
Workers& m_workers;
};
private:
static void deleteWorkers (LockFreeStack <Worker>& stack);
private:
Callback& m_callback;
String m_threadNames; // The name to give each thread
WaitableEvent m_allPaused; // signaled when all threads paused
semaphore m_semaphore; // each pending task is 1 resource
int m_numberOfThreads; // how many we want active now
Atomic <int> m_activeCount; // to know when all are paused
Atomic <int> m_pauseCount; // how many threads need to pause now
Atomic <int> m_runningTaskCount; // how many calls to processTask() active
LockFreeStack <Worker> m_everyone; // holds all created workers
LockFreeStack <Worker, PausedTag> m_paused; // holds just paused workers
};
} // beast
#endif

View File

@@ -0,0 +1,257 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CORE_THREAD_DETAIL_SCOPEDLOCK_H_INCLUDED
#define BEAST_CORE_THREAD_DETAIL_SCOPEDLOCK_H_INCLUDED
#include <beast/module/beast_core/thread/MutexTraits.h>
namespace beast
{
namespace detail
{
template <typename Mutex>
class TrackedScopedLock : public Uncopyable
{
public:
inline explicit TrackedScopedLock (Mutex const& mutex,
char const* fileName, int lineNumber) noexcept
: m_mutex (mutex)
, m_lock_count (0)
{
lock (fileName, lineNumber);
}
inline ~TrackedScopedLock () noexcept
{
if (m_lock_count > 0)
unlock ();
}
inline void lock (char const* fileName, int lineNumber) noexcept
{
++m_lock_count;
m_mutex.lock (fileName, lineNumber);
}
inline void unlock () noexcept
{
m_mutex.unlock ();
--m_lock_count;
}
private:
Mutex const& m_mutex;
int m_lock_count;
};
//--------------------------------------------------------------------------
template <typename Mutex>
class TrackedScopedTryLock : public Uncopyable
{
public:
inline explicit TrackedScopedTryLock (Mutex const& mutex,
char const* fileName, int lineNumber) noexcept
: m_mutex (mutex)
, m_lock_count (0)
{
try_lock (fileName, lineNumber);
}
inline ~TrackedScopedTryLock () noexcept
{
if (m_lock_count > 0)
unlock ();
}
inline bool owns_lock () const noexcept
{
return m_lock_count > 0;
}
inline bool try_lock (char const* fileName, int lineNumber) noexcept
{
bool const success = m_mutex.try_lock (fileName, lineNumber);
if (success)
++m_lock_count;
return success;
}
inline void unlock () noexcept
{
m_mutex.unlock ();
--m_lock_count;
}
private:
Mutex const& m_mutex;
int m_lock_count;
};
//--------------------------------------------------------------------------
template <typename Mutex>
class TrackedScopedUnlock : public Uncopyable
{
public:
inline explicit TrackedScopedUnlock (Mutex const& mutex,
char const* fileName, int lineNumber) noexcept
: m_mutex (mutex)
, m_fileName (fileName)
, m_lineNumber (lineNumber)
{
m_mutex.unlock ();
}
inline ~TrackedScopedUnlock () noexcept
{
m_mutex.lock (m_fileName, m_lineNumber);
}
private:
Mutex const& m_mutex;
char const* const m_fileName;
int const m_lineNumber;
};
//--------------------------------------------------------------------------
template <typename Mutex>
class UntrackedScopedLock : public Uncopyable
{
public:
inline explicit UntrackedScopedLock (Mutex const& mutex,
char const*, int) noexcept
: m_mutex (mutex)
, m_lock_count (0)
{
lock ();
}
inline ~UntrackedScopedLock () noexcept
{
if (m_lock_count > 0)
unlock ();
}
inline void lock () noexcept
{
++m_lock_count;
m_mutex.lock ();
}
inline void lock (char const*, int) noexcept
{
lock ();
}
inline void unlock () noexcept
{
m_mutex.unlock ();
--m_lock_count;
}
private:
Mutex const& m_mutex;
int m_lock_count;
};
//--------------------------------------------------------------------------
template <typename Mutex>
class UntrackedScopedTryLock : public Uncopyable
{
public:
inline explicit UntrackedScopedTryLock (Mutex const& mutex,
char const*, int) noexcept
: m_mutex (mutex)
, m_lock_count (0)
{
try_lock ();
}
inline ~UntrackedScopedTryLock () noexcept
{
if (m_lock_count > 0)
unlock ();
}
inline bool owns_lock () const noexcept
{
return m_lock_count > 0;
}
inline bool try_lock () noexcept
{
bool const success = m_mutex.try_lock ();
if (success)
++m_lock_count;
return success;
}
inline bool try_lock (char const*, int) noexcept
{
return try_lock ();
}
inline void unlock () noexcept
{
m_mutex.unlock ();
--m_lock_count;
}
private:
Mutex const& m_mutex;
int m_lock_count;
};
//--------------------------------------------------------------------------
template <typename Mutex>
class UntrackedScopedUnlock : public Uncopyable
{
public:
UntrackedScopedUnlock (Mutex const& mutex,
char const*, int) noexcept
: m_mutex (mutex)
, m_owns_lock (true)
{
MutexTraits <Mutex>::unlock (m_mutex);
m_owns_lock = false;
}
~UntrackedScopedUnlock () noexcept
{
MutexTraits <Mutex>::lock (m_mutex);
m_owns_lock = true;
}
private:
Mutex const& m_mutex;
bool m_owns_lock;
};
} // detail
} // beast
#endif

View File

@@ -0,0 +1,261 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CRITICALSECTION_H_INCLUDED
#define BEAST_CRITICALSECTION_H_INCLUDED
#include <beast/module/core/threads/ScopedLock.h>
namespace beast {
//==============================================================================
/**
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.
@see ScopedLock, ScopedTryLock, ScopedUnlock, SpinLock, Thread
*/
class CriticalSection : public Uncopyable
{
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. */
typedef GenericScopedLock <CriticalSection> ScopedLockType;
/** Provides the type of scoped unlocker to use with a CriticalSection. */
typedef GenericScopedUnlock <CriticalSection> ScopedUnlockType;
/** Provides the type of scoped try-locker to use with a CriticalSection. */
typedef GenericScopedTryLock <CriticalSection> ScopedTryLockType;
//--------------------------------------------------------------------------
//
// Boost concept compatibility
// http://www.boost.org/doc/libs/1_54_0/doc/html/thread/synchronization.html#thread.synchronization.mutex_concepts
//
// BasicLockable
inline void lock () const noexcept { enter (); }
inline void unlock () const noexcept { exit (); }
// Lockable
inline bool try_lock () const noexcept { return tryEnter (); }
//--------------------------------------------------------------------------
private:
//==============================================================================
#if BEAST_WINDOWS
// To avoid including windows.h in the public Beast 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 BEAST_64BIT
std::uint8_t section[44];
#else
std::uint8_t section[24];
#endif
#else
mutable pthread_mutex_t mutex;
#endif
};
//==============================================================================
/**
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, SharedObjectArray
*/
class DummyCriticalSection : public Uncopyable
{
public:
inline DummyCriticalSection() noexcept {}
inline ~DummyCriticalSection() noexcept {}
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. */
typedef ScopedLockType ScopedUnlockType;
};
//==============================================================================
/**
Automatically locks and unlocks a CriticalSection object.
Use one of these as a local variable to provide RAII-based locking of a CriticalSection.
e.g. @code
CriticalSection myCriticalSection;
for (;;)
{
const ScopedLock myScopedLock (myCriticalSection);
// myCriticalSection is now locked
...do some stuff...
// myCriticalSection gets unlocked here.
}
@endcode
@see CriticalSection, ScopedUnlock
*/
typedef CriticalSection::ScopedLockType ScopedLock;
//==============================================================================
/**
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
CriticalSection myCriticalSection;
for (;;)
{
const ScopedLock myScopedLock (myCriticalSection);
// myCriticalSection is now locked
... do some stuff with it locked ..
while (xyz)
{
... do some stuff with it locked ..
const ScopedUnlock 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 CriticalSection, ScopedLock
*/
typedef CriticalSection::ScopedUnlockType ScopedUnlock;
//==============================================================================
/**
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
CriticalSection myCriticalSection;
for (;;)
{
const ScopedTryLock 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, ScopedLock, ScopedUnlock, ScopedReadLock
*/
typedef CriticalSection::ScopedTryLockType ScopedTryLock;
} // beast
#endif // BEAST_CRITICALSECTION_H_INCLUDED

View File

@@ -0,0 +1,82 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_DYNAMICLIBRARY_H_INCLUDED
#define BEAST_DYNAMICLIBRARY_H_INCLUDED
namespace beast
{
/**
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.
*/
class DynamicLibrary : LeakChecked <DynamicLibrary>, public Uncopyable
{
public:
/** Creates an unopened DynamicLibrary object.
Call open() to actually open one.
*/
DynamicLibrary() noexcept : handle (nullptr) {}
/**
*/
DynamicLibrary (const String& name) : handle (nullptr) { open (name); }
/** 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;
};
} // beast
#endif // BEAST_DYNAMICLIBRARY_H_INCLUDED

View File

@@ -0,0 +1,138 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_PROCESS_H_INCLUDED
#define BEAST_PROCESS_H_INCLUDED
namespace beast {
//==============================================================================
/** Represents the current executable's process.
This contains methods for controlling the current application at the
process-level.
@see Thread, BEASTApplication
*/
class Process : public Uncopyable
{
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 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 BEASTApplication::quit
*/
static void terminate();
//==============================================================================
/** Returns true if this application process is the one that the user is
currently using.
*/
static bool isForegroundProcess();
/** Attempts to make the current process the active one.
(This is not possible on some platforms).
*/
static void makeForegroundProcess();
//==============================================================================
/** 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 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 lowerPrivilege();
/** Returns true if this process is being hosted by a debugger. */
static bool isRunningUnderDebugger();
//==============================================================================
/** Tries to launch the OS's default reader application for a given file or URL. */
static bool openDocument (const String& documentURL, const String& parameters);
#if BEAST_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 BEAST application, this will be automatically set to the module
handle of the executable.
If you've built a DLL and plan to use any BEAST 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* 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 setCurrentModuleInstanceHandle (void* newHandle) noexcept;
#endif
#if BEAST_MAC || DOXYGEN
//==============================================================================
/** OSX ONLY - Shows or hides the OSX dock icon for this app. */
static void setDockIconVisible (bool isVisible);
#endif
private:
Process();
};
} // beast
#endif // BEAST_PROCESS_H_INCLUDED

View File

@@ -0,0 +1,249 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SCOPEDLOCK_H_INCLUDED
#define BEAST_SCOPEDLOCK_H_INCLUDED
namespace beast
{
//==============================================================================
/**
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
*/
template <class LockType>
class GenericScopedLock : public Uncopyable
{
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_;
};
//==============================================================================
/**
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
*/
template <class LockType>
class GenericScopedUnlock : public Uncopyable
{
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 (LockType& lock) noexcept
: lock_ (lock)
{
lock.unlock();
}
/** 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_.lock();
}
private:
//==============================================================================
LockType& lock_;
};
//==============================================================================
/**
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
*/
template <class LockType>
class GenericScopedTryLock : public Uncopyable
{
public:
//==============================================================================
/** Creates a GenericScopedTryLock.
As soon as it is created, this will attempt to acquire the lock, and when the
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.
*/
inline explicit GenericScopedTryLock (const LockType& lock) noexcept
: lock_ (lock), lockWasSuccessful (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;
}
private:
//==============================================================================
const LockType& lock_;
const bool lockWasSuccessful;
};
} // beast
#endif

View File

@@ -0,0 +1,141 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
// Manages the list of hooks, and calls
// whoever is in the list at exit time.
//
class AtExitHook::Manager
{
public:
Manager ()
: m_didStaticDestruction (false)
{
}
static inline Manager& get ()
{
return StaticObject <Manager>::get();
}
void insert (Item& item)
{
ScopedLockType lock (m_mutex);
// Adding a new AtExitHook during or after the destruction
// of objects with static storage duration has taken place?
// Surely something has gone wrong.
//
bassert (! m_didStaticDestruction);
m_list.push_front (item);
}
void erase (Item& item)
{
ScopedLockType lock (m_mutex);
m_list.erase (m_list.iterator_to (item));
}
private:
// Called at program exit when destructors for objects
// with static storage duration are invoked.
//
void doStaticDestruction ()
{
// In theory this shouldn't be needed (?)
ScopedLockType lock (m_mutex);
bassert (! m_didStaticDestruction);
m_didStaticDestruction = true;
for (List <Item>::iterator iter (m_list.begin()); iter != m_list.end();)
{
Item& item (*iter++);
AtExitHook* const hook (item.hook ());
hook->onExit ();
}
// Now do the leak checking
//
LeakCheckedBase::checkForLeaks ();
}
struct StaticDestructor
{
~StaticDestructor ()
{
Manager::get().doStaticDestruction();
}
};
typedef CriticalSection MutexType;
typedef MutexType::ScopedLockType ScopedLockType;
static StaticDestructor s_staticDestructor;
MutexType m_mutex;
List <Item> m_list;
bool m_didStaticDestruction;
};
// This is an object with static storage duration.
// When it gets destroyed, we will call into the Manager to
// call all of the AtExitHook items in the list.
//
AtExitHook::Manager::StaticDestructor AtExitHook::Manager::s_staticDestructor;
//------------------------------------------------------------------------------
AtExitHook::Item::Item (AtExitHook* hook)
: m_hook (hook)
{
}
AtExitHook* AtExitHook::Item::hook ()
{
return m_hook;
}
//------------------------------------------------------------------------------
AtExitHook::AtExitHook ()
: m_item (this)
{
#if BEAST_IOS
// Patrick Dehne:
// AtExitHook::Manager::insert crashes on iOS
// if the storage is not accessed before it is used.
//
// VFALCO TODO Figure out why and fix it cleanly if needed.
//
char* hack = AtExitHook::Manager::s_list.s_storage;
#endif
Manager::get().insert (m_item);
}
AtExitHook::~AtExitHook ()
{
Manager::get().erase (m_item);
}
} // beast

View File

@@ -0,0 +1,94 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_CORE_ATEXITHOOK_H_INCLUDED
#define BEAST_CORE_ATEXITHOOK_H_INCLUDED
#include <beast/intrusive/List.h>
namespace beast {
/** Hook for performing activity on program exit.
These hooks execute when objects with static storage duration are
destroyed. The hooks are called in the reverse order that they were
created.
To use, derive your class from AtExitHook and implement onExit.
Alternatively, add AtExitMemberHook as a data member of your class and
then provide your own onExit function with this signature:
@code
void onExit ()
@endcode
@see AtExitMemberHook
*/
/** @{ */
class AtExitHook
{
protected:
AtExitHook ();
virtual ~AtExitHook ();
protected:
/** Called at program exit. */
virtual void onExit () = 0;
private:
class Manager;
class Item : public List <Item>::Node
{
public:
explicit Item (AtExitHook* hook);
AtExitHook* hook ();
private:
AtExitHook* m_hook;
};
Item m_item;
};
/** Helper for utilizing the AtExitHook as a data member.
*/
template <class Object>
class AtExitMemberHook : public AtExitHook
{
public:
explicit AtExitMemberHook (Object* owner) : m_owner (owner)
{
}
private:
void onExit ()
{
m_owner->onExit ();
}
Object* m_owner;
};
/** @} */
} // beast
#endif

View File

@@ -0,0 +1,446 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
namespace beast
{
namespace TimeHelpers
{
static struct tm millisToLocal (const std::int64_t millis) noexcept
{
struct tm result;
const std::int64_t seconds = millis / 1000;
if (seconds < 86400LL || seconds >= 2145916800LL)
{
// use extended maths for dates beyond 1970 to 2037..
const int timeZoneAdjustment = 31536000 - (int) (Time (1971, 0, 1, 0, 0).toMilliseconds() / 1000);
const std::int64_t jdm = seconds + timeZoneAdjustment + 210866803200LL;
const int days = (int) (jdm / 86400LL);
const int a = 32044 + days;
const int b = (4 * a + 3) / 146097;
const int c = a - (b * 146097) / 4;
const int d = (4 * c + 3) / 1461;
const int e = c - (d * 1461) / 4;
const int m = (5 * e + 2) / 153;
result.tm_mday = e - (153 * m + 2) / 5 + 1;
result.tm_mon = m + 2 - 12 * (m / 10);
result.tm_year = b * 100 + d - 6700 + (m / 10);
result.tm_wday = (days + 1) % 7;
result.tm_yday = -1;
int t = (int) (jdm % 86400LL);
result.tm_hour = t / 3600;
t %= 3600;
result.tm_min = t / 60;
result.tm_sec = t % 60;
result.tm_isdst = -1;
}
else
{
time_t now = static_cast <time_t> (seconds);
#if BEAST_WINDOWS
#ifdef _INC_TIME_INL
if (now >= 0 && now <= 0x793406fff)
localtime_s (&result, &now);
else
zerostruct (result);
#else
result = *localtime (&now);
#endif
#else
localtime_r (&now, &result); // more thread-safe
#endif
}
return result;
}
static int extendedModulo (const std::int64_t value, const int modulo) noexcept
{
return (int) (value >= 0 ? (value % modulo)
: (value - ((value / modulo) + 1) * modulo));
}
static inline String formatString (const String& format, const struct tm* const tm)
{
#if BEAST_ANDROID
typedef CharPointer_UTF8 StringType;
#elif BEAST_WINDOWS
typedef CharPointer_UTF16 StringType;
#else
typedef CharPointer_UTF32 StringType;
#endif
for (size_t bufferSize = 256; ; bufferSize += 256)
{
HeapBlock<StringType::CharType> buffer (bufferSize);
#if BEAST_ANDROID
const size_t numChars = strftime (buffer, bufferSize - 1, format.toUTF8(), tm);
#elif BEAST_WINDOWS
const size_t numChars = wcsftime (buffer, bufferSize - 1, format.toWideCharPointer(), tm);
#else
const size_t numChars = wcsftime (buffer, bufferSize - 1, format.toUTF32(), tm);
#endif
if (numChars > 0)
return String (StringType (buffer),
StringType (buffer) + (int) numChars);
}
}
static std::uint32_t lastMSCounterValue = 0;
}
//==============================================================================
Time::Time() noexcept
: millisSinceEpoch (0)
{
}
Time::Time (const Time& other) noexcept
: millisSinceEpoch (other.millisSinceEpoch)
{
}
Time::Time (const std::int64_t ms) noexcept
: millisSinceEpoch (ms)
{
}
Time::Time (const int year,
const int month,
const int day,
const int hours,
const int minutes,
const int seconds,
const int milliseconds,
const bool useLocalTime) noexcept
{
bassert (year > 100); // year must be a 4-digit version
if (year < 1971 || year >= 2038 || ! useLocalTime)
{
// use extended maths for dates beyond 1970 to 2037..
const int timeZoneAdjustment = useLocalTime ? (31536000 - (int) (Time (1971, 0, 1, 0, 0).toMilliseconds() / 1000))
: 0;
const int a = (13 - month) / 12;
const int y = year + 4800 - a;
const int jd = day + (153 * (month + 12 * a - 2) + 2) / 5
+ (y * 365) + (y / 4) - (y / 100) + (y / 400)
- 32045;
const std::int64_t s = ((std::int64_t) jd) * 86400LL - 210866803200LL;
millisSinceEpoch = 1000 * (s + (hours * 3600 + minutes * 60 + seconds - timeZoneAdjustment))
+ milliseconds;
}
else
{
struct tm t;
t.tm_year = year - 1900;
t.tm_mon = month;
t.tm_mday = day;
t.tm_hour = hours;
t.tm_min = minutes;
t.tm_sec = seconds;
t.tm_isdst = -1;
millisSinceEpoch = 1000 * (std::int64_t) mktime (&t);
if (millisSinceEpoch < 0)
millisSinceEpoch = 0;
else
millisSinceEpoch += milliseconds;
}
}
Time::~Time() noexcept
{
}
Time& Time::operator= (const Time& other) noexcept
{
millisSinceEpoch = other.millisSinceEpoch;
return *this;
}
//==============================================================================
std::int64_t Time::currentTimeMillis() noexcept
{
#if BEAST_WINDOWS
struct _timeb t;
#ifdef _INC_TIME_INL
_ftime_s (&t);
#else
_ftime (&t);
#endif
return ((std::int64_t) t.time) * 1000 + t.millitm;
#else
struct timeval tv;
gettimeofday (&tv, nullptr);
return ((std::int64_t) tv.tv_sec) * 1000 + tv.tv_usec / 1000;
#endif
}
Time Time::getCurrentTime() noexcept
{
return Time (currentTimeMillis());
}
//==============================================================================
std::uint32_t beast_millisecondsSinceStartup() noexcept;
std::uint32_t Time::getMillisecondCounter() noexcept
{
const std::uint32_t now = beast_millisecondsSinceStartup();
if (now < TimeHelpers::lastMSCounterValue)
{
// in multi-threaded apps this might be called concurrently, so
// make sure that our last counter value only increases and doesn't
// go backwards..
if (now < TimeHelpers::lastMSCounterValue - 1000)
TimeHelpers::lastMSCounterValue = now;
}
else
{
TimeHelpers::lastMSCounterValue = now;
}
return now;
}
std::uint32_t Time::getApproximateMillisecondCounter() noexcept
{
if (TimeHelpers::lastMSCounterValue == 0)
getMillisecondCounter();
return TimeHelpers::lastMSCounterValue;
}
void Time::waitForMillisecondCounter (const std::uint32_t targetTime) noexcept
{
for (;;)
{
const std::uint32_t now = getMillisecondCounter();
if (now >= targetTime)
break;
const int toWait = (int) (targetTime - now);
if (toWait > 2)
{
Thread::sleep (bmin (20, toWait >> 1));
}
else
{
// xxx should consider using mutex_pause on the mac as it apparently
// makes it seem less like a spinlock and avoids lowering the thread pri.
for (int i = 10; --i >= 0;)
Thread::yield();
}
}
}
//==============================================================================
double Time::highResolutionTicksToSeconds (const std::int64_t ticks) noexcept
{
return ticks / (double) getHighResolutionTicksPerSecond();
}
std::int64_t Time::secondsToHighResolutionTicks (const double seconds) noexcept
{
return (std::int64_t) (seconds * (double) getHighResolutionTicksPerSecond());
}
//==============================================================================
String Time::toString (const bool includeDate,
const bool includeTime,
const bool includeSeconds,
const bool use24HourClock) const noexcept
{
String result;
if (includeDate)
{
result << getDayOfMonth() << ' '
<< getMonthName (true) << ' '
<< getYear();
if (includeTime)
result << ' ';
}
if (includeTime)
{
const int mins = getMinutes();
result << (use24HourClock ? getHours() : getHoursInAmPmFormat())
<< (mins < 10 ? ":0" : ":") << mins;
if (includeSeconds)
{
const int secs = getSeconds();
result << (secs < 10 ? ":0" : ":") << secs;
}
if (! use24HourClock)
result << (isAfternoon() ? "pm" : "am");
}
return result.trimEnd();
}
String Time::formatted (const String& format) const
{
struct tm t (TimeHelpers::millisToLocal (millisSinceEpoch));
return TimeHelpers::formatString (format, &t);
}
//==============================================================================
int Time::getYear() const noexcept { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_year + 1900; }
int Time::getMonth() const noexcept { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_mon; }
int Time::getDayOfYear() const noexcept { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_yday; }
int Time::getDayOfMonth() const noexcept { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_mday; }
int Time::getDayOfWeek() const noexcept { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_wday; }
int Time::getHours() const noexcept { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_hour; }
int Time::getMinutes() const noexcept { return TimeHelpers::millisToLocal (millisSinceEpoch).tm_min; }
int Time::getSeconds() const noexcept { return TimeHelpers::extendedModulo (millisSinceEpoch / 1000, 60); }
int Time::getMilliseconds() const noexcept { return TimeHelpers::extendedModulo (millisSinceEpoch, 1000); }
int Time::getHoursInAmPmFormat() const noexcept
{
const int hours = getHours();
if (hours == 0) return 12;
if (hours <= 12) return hours;
return hours - 12;
}
bool Time::isAfternoon() const noexcept
{
return getHours() >= 12;
}
bool Time::isDaylightSavingTime() const noexcept
{
return TimeHelpers::millisToLocal (millisSinceEpoch).tm_isdst != 0;
}
String Time::getTimeZone() const noexcept
{
String zone[2];
#if BEAST_WINDOWS
_tzset();
#ifdef _INC_TIME_INL
for (int i = 0; i < 2; ++i)
{
char name[128] = { 0 };
size_t length;
_get_tzname (&length, name, 127, i);
zone[i] = name;
}
#else
const char** const zonePtr = (const char**) _tzname;
zone[0] = zonePtr[0];
zone[1] = zonePtr[1];
#endif
#else
tzset();
const char** const zonePtr = (const char**) tzname;
zone[0] = zonePtr[0];
zone[1] = zonePtr[1];
#endif
if (isDaylightSavingTime())
{
zone[0] = zone[1];
if (zone[0].length() > 3
&& zone[0].containsIgnoreCase ("daylight")
&& zone[0].contains ("GMT"))
zone[0] = "BST";
}
return zone[0].substring (0, 3);
}
String Time::getMonthName (const bool threeLetterVersion) const
{
return getMonthName (getMonth(), threeLetterVersion);
}
String Time::getWeekdayName (const bool threeLetterVersion) const
{
return getWeekdayName (getDayOfWeek(), threeLetterVersion);
}
String Time::getMonthName (int monthNumber, const bool threeLetterVersion)
{
const char* const shortMonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
const char* const longMonthNames[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
monthNumber %= 12;
return threeLetterVersion ? shortMonthNames [monthNumber]
: longMonthNames [monthNumber];
}
String Time::getWeekdayName (int day, const bool threeLetterVersion)
{
const char* const shortDayNames[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
const char* const longDayNames[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
day %= 7;
return threeLetterVersion ? shortDayNames [day]
: longDayNames [day];
}
//==============================================================================
Time& Time::operator+= (RelativeTime delta) { millisSinceEpoch += delta.inMilliseconds(); return *this; }
Time& Time::operator-= (RelativeTime delta) { millisSinceEpoch -= delta.inMilliseconds(); return *this; }
Time operator+ (Time time, RelativeTime delta) { Time t (time); return t += delta; }
Time operator- (Time time, RelativeTime delta) { Time t (time); return t -= delta; }
Time operator+ (RelativeTime delta, Time time) { Time t (time); return t += delta; }
const RelativeTime operator- (Time time1, Time time2) { return RelativeTime::milliseconds (time1.toMilliseconds() - time2.toMilliseconds()); }
bool operator== (Time time1, Time time2) { return time1.toMilliseconds() == time2.toMilliseconds(); }
bool operator!= (Time time1, Time time2) { return time1.toMilliseconds() != time2.toMilliseconds(); }
bool operator< (Time time1, Time time2) { return time1.toMilliseconds() < time2.toMilliseconds(); }
bool operator> (Time time1, Time time2) { return time1.toMilliseconds() > time2.toMilliseconds(); }
bool operator<= (Time time1, Time time2) { return time1.toMilliseconds() <= time2.toMilliseconds(); }
bool operator>= (Time time1, Time time2) { return time1.toMilliseconds() >= time2.toMilliseconds(); }
} // beast

View File

@@ -0,0 +1,418 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_TIME_H_INCLUDED
#define BEAST_TIME_H_INCLUDED
#include <beast/chrono/RelativeTime.h>
namespace beast {
//==============================================================================
/**
Holds an absolute date and time.
Internally, the time is stored at millisecond precision.
@see RelativeTime
*/
class Time
{
public:
//==============================================================================
/** Creates a Time object.
This default constructor creates a time of 1st January 1970, (which is
represented internally as 0ms).
To create a time object representing the current time, use getCurrentTime().
@see getCurrentTime
*/
Time() noexcept;
/** Creates a time based on a number of milliseconds.
The internal millisecond count is set to 0 (1st January 1970). 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).
@see getCurrentTime, currentTimeMillis
*/
explicit Time (std::int64_t millisecondsSinceEpoch) noexcept;
/** Creates a time from a set of date components.
The timezone is assumed to be whatever the system is using as its locale.
@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, encode using the current machine's local time; if
false, it will always work in GMT.
*/
Time (int year,
int month,
int day,
int hours,
int minutes,
int seconds = 0,
int milliseconds = 0,
bool useLocalTime = true) noexcept;
/** Creates a copy of another Time object. */
Time (const Time& other) noexcept;
/** Destructor. */
~Time() noexcept;
/** Copies this time from another one. */
Time& operator= (const Time& other) noexcept;
//==============================================================================
/** Returns a Time object that is set to the current system time.
@see currentTimeMillis
*/
static Time getCurrentTime() noexcept;
/** Returns `true` if this object represents "no time", or NULL.
Internally we check for milliseconds since Epoch equal to zero.
*/
/** @{ */
bool isNull () const noexcept
{
return millisSinceEpoch == 0;
}
bool isNotNull () const noexcept
{
return millisSinceEpoch != 0;
}
/** @} */
/** Returns the time as a number of milliseconds.
@returns the number of milliseconds this Time object represents, since
midnight jan 1st 1970.
@see getMilliseconds
*/
std::int64_t toMilliseconds() const noexcept { return millisSinceEpoch; }
/** Returns the year.
A 4-digit format is used, e.g. 2004.
*/
int getYear() const noexcept;
/** Returns the number of the month.
The value returned is in the range 0 to 11.
@see getMonthName
*/
int getMonth() const noexcept;
/** Returns the name of the month.
@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.
The value returned is in the range 1 to 31.
*/
int getDayOfMonth() const noexcept;
/** Returns the number of the day of the week.
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.
The value returned is in the range 0 to 365.
*/
int getDayOfYear() const noexcept;
/** Returns the name of the weekday.
@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.
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.
So it returns true for "PM", false for "AM".
@see getHoursInAmPmFormat, getHours
*/
bool isAfternoon() const noexcept;
/** Returns the hours in 12-hour clock format.
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. */
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 noexcept;
//==============================================================================
/** Quick way of getting a string version of a date and time.
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 noexcept;
/** 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,61].
%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;
//==============================================================================
/** Adds a RelativeTime to this time. */
Time& operator+= (RelativeTime delta);
/** Subtracts a RelativeTime from this time. */
Time& operator-= (RelativeTime delta);
//==============================================================================
/** 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.
Should be accurate to within a few millisecs, depending on platform,
hardware, etc.
*/
static std::int64_t currentTimeMillis() noexcept;
/** Returns the number of millisecs since a fixed event (usually system startup).
This returns a monotonically increasing value which it 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 std::uint32_t 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 (std::uint32_t 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 std::uint32_t 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 std::int64_t getHighResolutionTicks() noexcept;
/** Returns the resolution of the high-resolution counter in ticks per second.
@see getHighResolutionTicks, highResolutionTicksToSeconds,
secondsToHighResolutionTicks
*/
static std::int64_t getHighResolutionTicksPerSecond() noexcept;
/** Converts a number of high-resolution ticks into seconds.
@see getHighResolutionTicks, getHighResolutionTicksPerSecond,
secondsToHighResolutionTicks
*/
static double highResolutionTicksToSeconds (std::int64_t ticks) noexcept;
/** Converts a number seconds into high-resolution ticks.
@see getHighResolutionTicks, getHighResolutionTicksPerSecond,
highResolutionTicksToSeconds
*/
static std::int64_t secondsToHighResolutionTicks (double seconds) noexcept;
private:
//==============================================================================
std::int64_t millisSinceEpoch;
};
//==============================================================================
/** Adds a RelativeTime to a Time. */
Time operator+ (Time time, RelativeTime delta);
/** Adds a RelativeTime to a Time. */
Time operator+ (RelativeTime delta, Time time);
/** Subtracts a RelativeTime from a Time. */
Time operator- (Time time, RelativeTime delta);
/** Returns the relative time difference between two times. */
const RelativeTime operator- (Time time1, Time time2);
/** Compares two Time objects. */
bool operator== (Time time1, Time time2);
/** Compares two Time objects. */
bool operator!= (Time time1, Time time2);
/** Compares two Time objects. */
bool operator< (Time time1, Time time2);
/** Compares two Time objects. */
bool operator<= (Time time1, Time time2);
/** Compares two Time objects. */
bool operator> (Time time1, Time time2);
/** Compares two Time objects. */
bool operator>= (Time time1, Time time2);
} // beast
#endif // BEAST_TIME_H_INCLUDED