mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-02 17:06:00 +00:00
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:
1059
beast/module/core/containers/Array.h
Normal file
1059
beast/module/core/containers/Array.h
Normal file
File diff suppressed because it is too large
Load Diff
135
beast/module/core/containers/ArrayAllocationBase.h
Normal file
135
beast/module/core/containers/ArrayAllocationBase.h
Normal 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
|
||||
194
beast/module/core/containers/ElementComparator.h
Normal file
194
beast/module/core/containers/ElementComparator.h
Normal 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
|
||||
|
||||
365
beast/module/core/containers/LinkedListPointer.h
Normal file
365
beast/module/core/containers/LinkedListPointer.h
Normal 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
|
||||
96
beast/module/core/containers/ScopedValueSetter.h
Normal file
96
beast/module/core/containers/ScopedValueSetter.h
Normal 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
184
beast/module/core/core.h
Normal 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
|
||||
237
beast/module/core/core.unity.cpp
Normal file
237
beast/module/core/core.unity.cpp
Normal 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>
|
||||
30
beast/module/core/core.unity.mm
Normal file
30
beast/module/core/core.unity.mm
Normal 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
|
||||
128
beast/module/core/diagnostic/FatalError.cpp
Normal file
128
beast/module/core/diagnostic/FatalError.cpp
Normal 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
|
||||
154
beast/module/core/diagnostic/FatalError.h
Normal file
154
beast/module/core/diagnostic/FatalError.h
Normal 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
|
||||
85
beast/module/core/diagnostic/MeasureFunctionCallTime.h
Normal file
85
beast/module/core/diagnostic/MeasureFunctionCallTime.h
Normal 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
|
||||
521
beast/module/core/diagnostic/SemanticVersion.cpp
Normal file
521
beast/module/core/diagnostic/SemanticVersion.cpp
Normal 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
|
||||
79
beast/module/core/diagnostic/SemanticVersion.h
Normal file
79
beast/module/core/diagnostic/SemanticVersion.h
Normal 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
|
||||
24
beast/module/core/diagnostic/UnitTestUtilities.cpp
Normal file
24
beast/module/core/diagnostic/UnitTestUtilities.cpp
Normal 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
|
||||
105
beast/module/core/diagnostic/UnitTestUtilities.h
Normal file
105
beast/module/core/diagnostic/UnitTestUtilities.h
Normal 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
|
||||
159
beast/module/core/files/DirectoryIterator.cpp
Normal file
159
beast/module/core/files/DirectoryIterator.cpp
Normal 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
|
||||
151
beast/module/core/files/DirectoryIterator.h
Normal file
151
beast/module/core/files/DirectoryIterator.h
Normal 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
|
||||
1069
beast/module/core/files/File.cpp
Normal file
1069
beast/module/core/files/File.cpp
Normal file
File diff suppressed because it is too large
Load Diff
966
beast/module/core/files/File.h
Normal file
966
beast/module/core/files/File.h
Normal 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
|
||||
|
||||
95
beast/module/core/files/FileInputStream.cpp
Normal file
95
beast/module/core/files/FileInputStream.cpp
Normal 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
|
||||
95
beast/module/core/files/FileInputStream.h
Normal file
95
beast/module/core/files/FileInputStream.h
Normal 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
|
||||
135
beast/module/core/files/FileOutputStream.cpp
Normal file
135
beast/module/core/files/FileOutputStream.cpp
Normal 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
|
||||
115
beast/module/core/files/FileOutputStream.h
Normal file
115
beast/module/core/files/FileOutputStream.h
Normal 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
|
||||
171
beast/module/core/files/FileSearchPath.cpp
Normal file
171
beast/module/core/files/FileSearchPath.cpp
Normal 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
|
||||
163
beast/module/core/files/FileSearchPath.h
Normal file
163
beast/module/core/files/FileSearchPath.h
Normal 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
|
||||
274
beast/module/core/files/RandomAccessFile.cpp
Normal file
274
beast/module/core/files/RandomAccessFile.cpp
Normal 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
|
||||
200
beast/module/core/files/RandomAccessFile.h
Normal file
200
beast/module/core/files/RandomAccessFile.h
Normal 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
|
||||
|
||||
117
beast/module/core/files/TemporaryFile.cpp
Normal file
117
beast/module/core/files/TemporaryFile.cpp
Normal 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
|
||||
166
beast/module/core/files/TemporaryFile.h
Normal file
166
beast/module/core/files/TemporaryFile.h
Normal 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
|
||||
63
beast/module/core/logging/Logger.cpp
Normal file
63
beast/module/core/logging/Logger.cpp
Normal 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
|
||||
93
beast/module/core/logging/Logger.h
Normal file
93
beast/module/core/logging/Logger.h
Normal 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
|
||||
89
beast/module/core/maths/Math.h
Normal file
89
beast/module/core/maths/Math.h
Normal 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
|
||||
155
beast/module/core/maths/Random.cpp
Normal file
155
beast/module/core/maths/Random.cpp
Normal 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
|
||||
128
beast/module/core/maths/Random.h
Normal file
128
beast/module/core/maths/Random.h
Normal 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
|
||||
263
beast/module/core/maths/Range.h
Normal file
263
beast/module/core/maths/Range.h
Normal 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
|
||||
410
beast/module/core/memory/MemoryBlock.cpp
Normal file
410
beast/module/core/memory/MemoryBlock.cpp
Normal 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
|
||||
274
beast/module/core/memory/MemoryBlock.h
Normal file
274
beast/module/core/memory/MemoryBlock.h
Normal 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
|
||||
|
||||
202
beast/module/core/memory/SharedSingleton.h
Normal file
202
beast/module/core/memory/SharedSingleton.h
Normal 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
|
||||
83
beast/module/core/misc/Result.cpp
Normal file
83
beast/module/core/misc/Result.cpp
Normal 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
|
||||
122
beast/module/core/misc/Result.h
Normal file
122
beast/module/core/misc/Result.h
Normal 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
|
||||
|
||||
124
beast/module/core/misc/WindowsRegistry.h
Normal file
124
beast/module/core/misc/WindowsRegistry.h
Normal 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
|
||||
239
beast/module/core/native/BasicNativeHeaders.h
Normal file
239
beast/module/core/native/BasicNativeHeaders.h
Normal 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
|
||||
374
beast/module/core/native/bsd_Files.cpp
Normal file
374
beast/module/core/native/bsd_Files.cpp
Normal 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
|
||||
356
beast/module/core/native/bsd_SystemStats.cpp
Normal file
356
beast/module/core/native/bsd_SystemStats.cpp
Normal 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
|
||||
74
beast/module/core/native/bsd_Threads.cpp
Normal file
74
beast/module/core/native/bsd_Threads.cpp
Normal 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, ¶m);
|
||||
}
|
||||
|
||||
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
|
||||
374
beast/module/core/native/linux_Files.cpp
Normal file
374
beast/module/core/native/linux_Files.cpp
Normal 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
|
||||
181
beast/module/core/native/linux_SystemStats.cpp
Normal file
181
beast/module/core/native/linux_SystemStats.cpp
Normal 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
|
||||
89
beast/module/core/native/linux_Threads.cpp
Normal file
89
beast/module/core/native/linux_Threads.cpp
Normal 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, ¶m);
|
||||
}
|
||||
|
||||
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
|
||||
484
beast/module/core/native/mac_Files.mm
Normal file
484
beast/module/core/native/mac_Files.mm
Normal 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
|
||||
96
beast/module/core/native/mac_Strings.mm
Normal file
96
beast/module/core/native/mac_Strings.mm
Normal 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
|
||||
296
beast/module/core/native/mac_SystemStats.mm
Normal file
296
beast/module/core/native/mac_SystemStats.mm
Normal 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
|
||||
86
beast/module/core/native/mac_Threads.mm
Normal file
86
beast/module/core/native/mac_Threads.mm
Normal 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
|
||||
154
beast/module/core/native/osx_ObjCHelpers.h
Normal file
154
beast/module/core/native/osx_ObjCHelpers.h
Normal 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
|
||||
749
beast/module/core/native/posix_SharedCode.h
Normal file
749
beast/module/core/native/posix_SharedCode.h
Normal 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(), ×) == 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
|
||||
170
beast/module/core/native/win32_ComSmartPtr.h
Normal file
170
beast/module/core/native/win32_ComSmartPtr.h
Normal 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
|
||||
835
beast/module/core/native/win32_Files.cpp
Normal file
835
beast/module/core/native/win32_Files.cpp
Normal 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
|
||||
219
beast/module/core/native/win32_Registry.cpp
Normal file
219
beast/module/core/native/win32_Registry.cpp
Normal 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
|
||||
423
beast/module/core/native/win32_SystemStats.cpp
Normal file
423
beast/module/core/native/win32_SystemStats.cpp
Normal 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
|
||||
189
beast/module/core/native/win32_Threads.cpp
Normal file
189
beast/module/core/native/win32_Threads.cpp
Normal 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
|
||||
56
beast/module/core/streams/FileInputSource.cpp
Normal file
56
beast/module/core/streams/FileInputSource.cpp
Normal 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
|
||||
65
beast/module/core/streams/FileInputSource.h
Normal file
65
beast/module/core/streams/FileInputSource.h
Normal 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
|
||||
71
beast/module/core/streams/InputSource.h
Normal file
71
beast/module/core/streams/InputSource.h
Normal 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
|
||||
326
beast/module/core/streams/InputStream.cpp
Normal file
326
beast/module/core/streams/InputStream.cpp
Normal 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
|
||||
360
beast/module/core/streams/InputStream.h
Normal file
360
beast/module/core/streams/InputStream.h
Normal 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
|
||||
214
beast/module/core/streams/MemoryOutputStream.cpp
Normal file
214
beast/module/core/streams/MemoryOutputStream.cpp
Normal 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
|
||||
145
beast/module/core/streams/MemoryOutputStream.h
Normal file
145
beast/module/core/streams/MemoryOutputStream.h
Normal 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
|
||||
438
beast/module/core/streams/OutputStream.cpp
Normal file
438
beast/module/core/streams/OutputStream.cpp
Normal 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
|
||||
304
beast/module/core/streams/OutputStream.h
Normal file
304
beast/module/core/streams/OutputStream.h
Normal 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
|
||||
32
beast/module/core/system/BeforeBoost.h
Normal file
32
beast/module/core/system/BeforeBoost.h
Normal 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
|
||||
32
beast/module/core/system/BoostIncludes.h
Normal file
32
beast/module/core/system/BoostIncludes.h
Normal 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
|
||||
42
beast/module/core/system/BoostPlaceholdersFix.cpp
Normal file
42
beast/module/core/system/BoostPlaceholdersFix.cpp
Normal 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
|
||||
64
beast/module/core/system/BoostPlaceholdersFix.h
Normal file
64
beast/module/core/system/BoostPlaceholdersFix.h
Normal 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
|
||||
381
beast/module/core/system/Functional.h
Normal file
381
beast/module/core/system/Functional.h
Normal 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
|
||||
54
beast/module/core/system/FunctionalIncludes.h
Normal file
54
beast/module/core/system/FunctionalIncludes.h
Normal 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
|
||||
78
beast/module/core/system/StandardIncludes.h
Normal file
78
beast/module/core/system/StandardIncludes.h
Normal 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
|
||||
165
beast/module/core/system/SystemStats.cpp
Normal file
165
beast/module/core/system/SystemStats.cpp
Normal 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
|
||||
185
beast/module/core/system/SystemStats.h
Normal file
185
beast/module/core/system/SystemStats.h
Normal 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
|
||||
106
beast/module/core/text/LexicalCast.cpp
Normal file
106
beast/module/core/text/LexicalCast.cpp
Normal 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
|
||||
242
beast/module/core/text/LexicalCast.h
Normal file
242
beast/module/core/text/LexicalCast.h
Normal 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
|
||||
515
beast/module/core/text/StringArray.cpp
Normal file
515
beast/module/core/text/StringArray.cpp
Normal 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
|
||||
414
beast/module/core/text/StringArray.h
Normal file
414
beast/module/core/text/StringArray.h
Normal 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
|
||||
149
beast/module/core/text/StringPairArray.cpp
Normal file
149
beast/module/core/text/StringPairArray.cpp
Normal 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
|
||||
162
beast/module/core/text/StringPairArray.h
Normal file
162
beast/module/core/text/StringPairArray.h
Normal 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
|
||||
248
beast/module/core/thread/DeadlineTimer.cpp
Normal file
248
beast/module/core/thread/DeadlineTimer.cpp
Normal 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
|
||||
116
beast/module/core/thread/DeadlineTimer.h
Normal file
116
beast/module/core/thread/DeadlineTimer.h
Normal 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
|
||||
80
beast/module/core/thread/MutexTraits.h
Normal file
80
beast/module/core/thread/MutexTraits.h
Normal 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
|
||||
299
beast/module/core/thread/Workers.cpp
Normal file
299
beast/module/core/thread/Workers.cpp
Normal 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
|
||||
149
beast/module/core/thread/Workers.h
Normal file
149
beast/module/core/thread/Workers.h
Normal 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
|
||||
257
beast/module/core/thread/detail/ScopedLock.h
Normal file
257
beast/module/core/thread/detail/ScopedLock.h
Normal 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
|
||||
261
beast/module/core/threads/CriticalSection.h
Normal file
261
beast/module/core/threads/CriticalSection.h
Normal 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
|
||||
82
beast/module/core/threads/DynamicLibrary.h
Normal file
82
beast/module/core/threads/DynamicLibrary.h
Normal 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
|
||||
138
beast/module/core/threads/Process.h
Normal file
138
beast/module/core/threads/Process.h
Normal 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
|
||||
249
beast/module/core/threads/ScopedLock.h
Normal file
249
beast/module/core/threads/ScopedLock.h
Normal 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
|
||||
|
||||
141
beast/module/core/time/AtExitHook.cpp
Normal file
141
beast/module/core/time/AtExitHook.cpp
Normal 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
|
||||
94
beast/module/core/time/AtExitHook.h
Normal file
94
beast/module/core/time/AtExitHook.h
Normal 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
|
||||
446
beast/module/core/time/Time.cpp
Normal file
446
beast/module/core/time/Time.cpp
Normal 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
|
||||
418
beast/module/core/time/Time.h
Normal file
418
beast/module/core/time/Time.h
Normal 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
|
||||
Reference in New Issue
Block a user