Merge branch 'master' into coord

This commit is contained in:
Danny Robson 2017-11-23 17:24:11 +11:00
commit 0351313c36
124 changed files with 5836 additions and 1986 deletions

1
.gitignore vendored
View File

@ -17,6 +17,7 @@
Makefile
Makefile.in
/missing
/preprocessor.hpp
/stamp-h1
/test-driver
/uri.cpp

View File

@ -13,7 +13,8 @@ include (nc)
include (search_libs)
find_package(RAGEL 6.9 REQUIRED)
find_package (PythonInterp 3 REQUIRED)
find_package (RAGEL 6.9 REQUIRED)
###############################################################################
@ -138,26 +139,26 @@ list (
algo/sort.hpp
algo/sort.ipp
alloc/fwd.hpp
alloc/affix.cpp
alloc/affix.hpp
alloc/aligned.hpp
alloc/allocator.cpp
alloc/allocator.hpp
alloc/allocator.ipp
alloc/arena.cpp
alloc/arena.hpp
alloc/arena.ipp
alloc/dynamic.hpp
alloc/fallback.cpp
alloc/fallback.hpp
alloc/linear.cpp
alloc/linear.hpp
alloc/malloc.cpp
alloc/malloc.hpp
alloc/null.cpp
alloc/null.hpp
alloc/stack.cpp
alloc/stack.hpp
alloc/raw/affix.cpp
alloc/raw/affix.hpp
alloc/raw/aligned.hpp
alloc/raw/dynamic.hpp
alloc/raw/fallback.cpp
alloc/raw/fallback.hpp
alloc/raw/linear.cpp
alloc/raw/linear.hpp
alloc/raw/malloc.cpp
alloc/raw/malloc.hpp
alloc/raw/null.cpp
alloc/raw/null.hpp
alloc/raw/stack.cpp
alloc/raw/stack.hpp
annotation.hpp
ascii.hpp
backtrace.hpp
@ -187,6 +188,8 @@ list (
crypto/arc4.hpp
crypto/ice.cpp
crypto/ice.hpp
crypto/salsa.cpp
crypto/salsa.hpp
crypto/tea.cpp
crypto/tea.hpp
crypto/xtea.cpp
@ -216,7 +219,6 @@ list (
geom/fwd.hpp
geom/aabb.cpp
geom/aabb.hpp
geom/aabb.ipp
geom/cylinder.cpp
geom/cylinder.hpp
geom/ellipse.cpp
@ -232,7 +234,6 @@ list (
geom/rect.cpp
geom/rect.hpp
geom/sample.hpp
geom/sample.ipp
geom/sphere.cpp
geom/sphere.hpp
geom/tri.cpp
@ -294,6 +295,8 @@ list (
io.hpp
io.ipp
iterator.hpp
job/queue.cpp
job/queue.hpp
json/fwd.hpp
json/except.cpp
json/except.hpp
@ -303,6 +306,18 @@ list (
json/schema.hpp
json/tree.cpp
json/tree.hpp
json2/fwd.hpp
json2/event.hpp
json2/event.cpp
json2/except.hpp
json2/personality/base.cpp
json2/personality/base.hpp
json2/personality/jsonish.cpp
json2/personality/jsonish.hpp
json2/personality/rfc7519.cpp
json2/personality/rfc7519.hpp
json2/tree.cpp
json2/tree.hpp
library.hpp
log.cpp
log.hpp
@ -318,6 +333,8 @@ list (
memory/deleter.cpp
memory/deleter.hpp
nocopy.hpp
parse.cpp
parse.hpp
pascal.cpp
pascal.hpp
platform.hpp
@ -391,6 +408,8 @@ list (
types/traits.hpp
uri.cpp
uri.hpp
utf8.cpp
utf8.hpp
variadic.cpp
variadic.hpp
vector.cpp
@ -399,11 +418,28 @@ list (
version.cpp
version.hpp
view.cpp
view.ipp
view.hpp
)
##-----------------------------------------------------------------------------
## We shouldn't be building into the source directory, but I can't stand trying
## to coax CMake into behaving here any longer. Feel free to fix it.
add_custom_command (
OUTPUT
"${CMAKE_CURRENT_SOURCE_DIR}/preprocessor.hpp"
COMMENT
"[preprocessor.py] preprocessor.hpp"
COMMAND
"${PYTHON_EXECUTABLE}"
"${CMAKE_CURRENT_SOURCE_DIR}/preprocessor.py"
"${CMAKE_CURRENT_SOURCE_DIR}/preprocessor.hpp"
320
DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/preprocessor.py"
)
###############################################################################
add_library(cruft-util ${UTIL_FILES})
target_link_libraries (cruft-util PUBLIC ${LIBS})
@ -457,9 +493,11 @@ if (TESTS)
coord
crypto/arc4
crypto/ice
crypto/salsa
crypto/tea
crypto/xtea
crypto/xxtea
endian
exe
extent
fixed
@ -484,13 +522,17 @@ if (TESTS)
hton
introspection
iterator
job/queue
json_types
json2/event
maths
matrix
memory/deleter
parse
point
polynomial
pool
preprocessor
quaternion
rand/buckets
range
@ -504,8 +546,10 @@ if (TESTS)
stringid
strongdef
tuple
traits
typeidx
uri
utf8
vector
version
view

View File

@ -30,20 +30,28 @@ namespace util::adapter {
m_target (_target)
{ ; }
auto begin (void) { return m_target.begin (); }
auto end (void) { return m_target.end (); }
auto begin (void) & { return m_target.rbegin (); }
auto end (void) & { return m_target.rend (); }
auto begin (void) const { return m_target.begin (); }
auto end (void) const { return m_target.end (); }
auto begin (void) const& { return m_target.rbegin (); }
auto end (void) const& { return m_target.rend (); }
auto cbegin (void) { return m_target.cbegin (); }
auto cend (void) { return m_target.cend (); }
auto cbegin (void) const& { return m_target.crbegin (); }
auto cend (void) const& { return m_target.crend (); }
private:
T &m_target;
};
template <typename Container>
auto
make_reverse (Container &c)
{
return reverse<Container> { c };
};
// adapt a container's range methods to return indices rather than iterators
template <typename T>
struct indices {

View File

@ -23,6 +23,8 @@
#include <utility>
namespace util::alloc {
/// wraps a block allocator with an interface suitable for allocating
/// individual objects.
template <class T>
class arena {
public:

View File

@ -1 +0,0 @@
#include "fallback.hpp"

View File

@ -19,17 +19,20 @@
namespace util::alloc {
class affix;
class fallback;
class linear;
class malloc;
class null;
class stack;
namespace raw {
class affix;
class fallback;
class linear;
class malloc;
class null;
class stack;
class dynamic;
class dynamic;
template <typename AllocT>
class aligned;
}
template <typename AllocT>
class aligned;
template <typename T> class arena;
template <typename B, typename T> class allocator;

View File

@ -16,7 +16,8 @@
#include "affix.hpp"
using util::alloc::affix;
using util::alloc::raw::affix;
///////////////////////////////////////////////////////////////////////////////

View File

@ -14,13 +14,20 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_ALLOC_AFFIX_HPP
#define __UTIL_ALLOC_AFFIX_HPP
#ifndef CRUFT_UTIL_ALLOC_RAW_AFFIX_HPP
#define CRUFT_UTIL_ALLOC_RAW_AFFIX_HPP
#include <cstddef>
namespace util::alloc {
template <class parent, class prefix, class suffix>
namespace util::alloc::raw {
/// a raw memory allocator which initialises an instance of PrefixT
/// immediately before each allocation and, if specified, an instance
/// of SuffixT after the allocation.
///
/// uses an instance of ParentT to actually perform the bulk allocations.
///
/// useful for sentinels, reference counts, etc.
template <class ParentT, class PrefixT, class SuffixT>
class affix {
void* allocate (size_t bytes);
void* allocate (size_t bytes, size_t align);
@ -28,8 +35,8 @@ namespace util::alloc {
void deallocate (void *ptr, size_t bytes);
void deallocate (void *ptr, size_t bytes, size_t align);
void* base (void);
const void* base (void) const;
void* begin (void);
const void* begin (void) const;
size_t offset (const void*) const;
};

View File

@ -14,17 +14,22 @@
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __CRUFT_UTIL_ALLOC_ALIGNED_HPP
#define __CRUFT_UTIL_ALLOC_ALIGNED_HPP
#ifndef CRUFT_UTIL_ALLOC_RAW_ALIGNED_HPP
#define CRUFT_UTIL_ALLOC_RAW_ALIGNED_HPP
namespace util::alloc {
#include <cstddef>
#include <utility>
#include "../../debug.hpp"
namespace util::alloc::raw {
/// wraps a child allocator and enforces a fixed alignment
template <typename ChildT>
class aligned {
public:
///////////////////////////////////////////////////////////////////////
template <typename ...Args>
aligned (size_t _alignment, Args &&...args):
aligned (std::size_t _alignment, Args &&...args):
m_successor (std::forward<Args> (args)...),
m_alignment (_alignment)
{ ; }
@ -32,14 +37,14 @@ namespace util::alloc {
///////////////////////////////////////////////////////////////////////
auto
allocate (size_t bytes)
allocate (std::size_t bytes)
{
return m_successor.allocate (bytes, m_alignment);
}
//---------------------------------------------------------------------
auto
allocate (size_t bytes, size_t alignment)
allocate (std::size_t bytes, std::size_t alignment)
{
(void)alignment;
CHECK_EQ (alignment, m_alignment);
@ -49,7 +54,7 @@ namespace util::alloc {
//---------------------------------------------------------------------
auto
deallocate (void *ptr, size_t bytes)
deallocate (void *ptr, std::size_t bytes)
{
return m_successor.deallocate (ptr, bytes);
}
@ -57,7 +62,7 @@ namespace util::alloc {
//---------------------------------------------------------------------
auto
deallocate (void *ptr, size_t bytes, size_t alignment)
deallocate (void *ptr, std::size_t bytes, std::size_t alignment)
{
(void)alignment;
CHECK_EQ (alignment, m_alignment);
@ -66,8 +71,8 @@ namespace util::alloc {
///////////////////////////////////////////////////////////////////////
auto base (void) { return m_successor.base (); }
auto base (void) const { return m_successor.base (); }
auto begin (void) { return m_successor.begin (); }
auto begin (void) const { return m_successor.begin (); }
//---------------------------------------------------------------------
@ -90,7 +95,7 @@ namespace util::alloc {
private:
ChildT m_successor;
size_t m_alignment;
std::size_t m_alignment;
};
}

View File

@ -14,13 +14,13 @@
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_ALLOC_DYNAMIC_HPP
#define __UTIL_ALLOC_DYNAMIC_HPP
#ifndef CRUFT_UTIL_ALLOC_RAW_DYNAMIC_HPP
#define CRUFT_UTIL_ALLOC_RAW_DYNAMIC_HPP
#include <cstddef>
#include <memory>
namespace util::alloc {
namespace util::alloc::raw {
// wraps an allocator given at construction time, forwarding all calls to
// the inner object. used to allow virtual dispatch of the non-virtual
// allocator interface.
@ -57,8 +57,8 @@ namespace util::alloc {
auto deallocate (void *ptr, size_t bytes, size_t alignment) { return m_child->deallocate (ptr, bytes, alignment); }
//---------------------------------------------------------------------
auto base (void) { return m_child->base (); }
auto base (void) const { return m_child->base (); }
auto begin (void) { return m_child->begin (); }
auto begin (void) const { return m_child->begin (); }
auto offset (const void *ptr) const
{ return m_child->offset (ptr); }
@ -93,8 +93,8 @@ namespace util::alloc {
virtual void deallocate (void *ptr, size_t bytes) = 0;
virtual void deallocate (void *ptr, size_t bytes, size_t alignment) = 0;
virtual void* base (void) = 0;
virtual const void* base (void) const = 0;
virtual void* begin (void) = 0;
virtual const void* begin (void) const = 0;
virtual size_t offset (const void*) const = 0;
virtual void reset (void) = 0;
@ -133,12 +133,12 @@ namespace util::alloc {
{ m_target.deallocate (ptr, bytes, alignment); }
const void*
base (void) const override
{ return m_target.base (); }
begin (void) const override
{ return m_target.begin (); }
void*
base (void) override
{ return m_target.base (); }
begin (void) override
{ return m_target.begin (); }
size_t
offset (const void *ptr) const override

17
alloc/raw/fallback.cpp Normal file
View File

@ -0,0 +1,17 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#include "./fallback.hpp"

View File

@ -11,25 +11,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_ALLOC_FALLBACK_HPP
#define __UTIL_ALLOC_FALLBACK_HPP
#ifndef CRUFT_UTIL_ALLOC_RAW_FALLBACK_HPP
#define CRUFT_UTIL_ALLOC_RAW_FALLBACK_HPP
#include <cstddef>
#include <tuple>
namespace util::alloc {
template <class A, class B>
namespace util::alloc::raw {
/// A raw memory allocator that allocates memory series of child
/// allocators, preferring earlier allocators.
template <typename ...ChildT>
class fallback {
public:
fallback (A&, B&);
fallback (ChildT &..._children):
m_children (_children...)
{ ; }
void* allocate (size_t bytes);
void* allocate (size_t bytes, size_t align);
void deallocate (void *ptr, size_t bytes);
void deallocate (void *ptr, size_t bytes, size_t align);
private:
std::tuple<ChildT&...> m_children;
};
}

View File

@ -16,10 +16,10 @@
#include "linear.hpp"
#include "../pointer.hpp"
#include "../debug.hpp"
#include "../../pointer.hpp"
#include "../../debug.hpp"
using util::alloc::linear;
using util::alloc::raw::linear;
///////////////////////////////////////////////////////////////////////////////
@ -30,7 +30,6 @@ linear::linear (void *begin, void *end):
{
CHECK_NEZ (begin);
CHECK_NEZ (end);
CHECK_LE (begin, end);
}
@ -78,7 +77,7 @@ linear::deallocate (void *ptr, size_t bytes, size_t alignment)
//-----------------------------------------------------------------------------
void*
linear::base (void)
linear::begin (void)
{
return m_begin;
}
@ -86,7 +85,7 @@ linear::base (void)
//-----------------------------------------------------------------------------
const void*
linear::base (void) const
linear::begin (void) const
{
return m_begin;
}

View File

@ -14,12 +14,13 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_ALLOC_LINEAR_HPP
#define __UTIL_ALLOC_LINEAR_HPP
#ifndef CRUFT_UTIL_ALLOC_RAW_LINEAR_HPP
#define CRUFT_UTIL_ALLOC_RAW_LINEAR_HPP
#include <cstddef>
#include <iterator>
namespace util::alloc {
namespace util::alloc::raw {
// allocate progressively across a buffer without concern for deallocation.
// deallocation is a noop; the only way to free allocations is via reset.
class linear {
@ -31,14 +32,25 @@ namespace util::alloc {
linear (void *begin, void *end);
template <typename T>
linear (T &&view):
linear (std::begin (view), std::end (view))
{ ; }
void* allocate (size_t bytes);
void* allocate (size_t bytes, size_t alignment);
void deallocate (void *ptr, size_t bytes);
void deallocate (void *ptr, size_t bytes, size_t alignment);
void* base (void);
const void* base (void) const;
void* begin (void);
void* end (void);
void* cursor (void);
const void* begin (void) const;
const void* end (void) const;
const void* cursor (void) const;
size_t offset (const void*) const;
void reset (void);

View File

@ -16,11 +16,11 @@
#include "malloc.hpp"
#include "../debug.hpp"
#include "../../debug.hpp"
#include <cstdlib>
using util::alloc::malloc;
using util::alloc::raw::malloc;
///////////////////////////////////////////////////////////////////////////////

View File

@ -14,13 +14,13 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_ALLOC_MALLOC_HPP
#define __UTIL_ALLOC_MALLOC_HPP
#ifndef CRUFT_UTIL_ALLOC_RAW_MALLOC_HPP
#define CRUFT_UTIL_ALLOC_RAW_MALLOC_HPP
#include <cstddef>
namespace util::alloc {
namespace util::alloc::raw {
class malloc {
public:
void* allocate (size_t bytes);
@ -32,4 +32,4 @@ namespace util::alloc {
}
#endif
#endif

View File

@ -17,11 +17,11 @@
#include "null.hpp"
#include "../debug.hpp"
#include "../../debug.hpp"
#include <new>
using util::alloc::null;
using util::alloc::raw::null;
///////////////////////////////////////////////////////////////////////////////
@ -68,7 +68,7 @@ null::deallocate (void *ptr, size_t bytes, size_t align)
///////////////////////////////////////////////////////////////////////////////
void*
null::base (void)
null::begin (void)
{
return nullptr;
}
@ -76,7 +76,7 @@ null::base (void)
//-----------------------------------------------------------------------------
const void*
null::base (void) const
null::begin (void) const
{
return nullptr;
}

View File

@ -14,13 +14,13 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_ALLOC_NULL_HPP
#define __UTIL_ALLOC_NULL_HPP
#ifndef CRUFT_UTIL_ALLOC_RAW_NULL_HPP
#define CRUFT_UTIL_ALLOC_RAW_NULL_HPP
#include <cstddef>
namespace util::alloc {
namespace util::alloc::raw {
// allocator that always fails, throwing bad_alloc. deallocate will
// succeed with nullptr as with delete, but is undefined with other values
// (it is likely to at least assert).
@ -35,8 +35,8 @@ namespace util::alloc {
void deallocate (void *ptr, size_t bytes);
void deallocate (void *ptr, size_t bytes, size_t align);
void* base (void);
const void* base (void) const;
void* begin (void);
const void* begin (void) const;
size_t offset (const void*) const;
void reset (void);

View File

@ -16,11 +16,11 @@
#include "stack.hpp"
#include "../debug.hpp"
#include "../pointer.hpp"
#include "../cast.hpp"
#include "../../debug.hpp"
#include "../../pointer.hpp"
#include "../../cast.hpp"
using util::alloc::stack;
using util::alloc::raw::stack;
///////////////////////////////////////////////////////////////////////////////
@ -113,7 +113,7 @@ stack::deallocate (void *_ptr, size_t bytes, size_t alignment)
//-----------------------------------------------------------------------------
void*
stack::base (void)
stack::begin (void)
{
return m_begin;
}
@ -121,7 +121,7 @@ stack::base (void)
//-----------------------------------------------------------------------------
const void*
stack::base (void) const
stack::begin (void) const
{
return m_begin;
}

View File

@ -14,13 +14,13 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_ALLOC_STACK_HPP
#define __UTIL_ALLOC_STACK_HPP
#ifndef CRUFT_UTIL_ALLOC_RAW_STACK_HPP
#define CRUFT_UTIL_ALLOC_RAW_STACK_HPP
#include <cstddef>
namespace util::alloc {
namespace util::alloc::raw {
// allocate memory from a buffer in a stacklike manner. deallocation that
// is not correctly ordered has undefined (read 'bad') results.
class stack {
@ -38,8 +38,8 @@ namespace util::alloc {
void deallocate (void *ptr, size_t bytes);
void deallocate (void *ptr, size_t bytes, size_t alignment);
void* base (void);
const void* base (void) const;
void* begin (void);
const void* begin (void) const;
size_t offset (const void*) const;
void reset (void);

View File

@ -60,7 +60,7 @@ addr2line (const void *addr)
);
// inefficient to copy from vector to string, but it's not a high priority path
auto data = util::slurp (stream.get ());
auto data = util::slurp<char> (stream.get ());
return std::string (data.cbegin (), data.cend ());
#else

View File

@ -11,14 +11,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2012-2016 Danny Robson <danny@nerdcruft.net>
* Copyright 2012-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_COORD_BASE_HPP
#define __UTIL_COORD_BASE_HPP
#ifndef CRUFT_UTIL_COORD_BASE_HPP
#define CRUFT_UTIL_COORD_BASE_HPP
#include "fwd.hpp"
#include "ops.hpp"
#include "init.hpp"
#include "traits.hpp"
#include "../maths.hpp"
@ -37,7 +38,7 @@ namespace util::coord {
// parameters are others (eg, vector2f). ie, it does not make sense to
// allow redim, or type changing on some types so they just aren't exposed.
template <
size_t S,
std::size_t S,
typename T,
typename SelfT
>
@ -47,17 +48,29 @@ namespace util::coord {
static_assert (sizeof (init<S,T,SelfT>) == S * sizeof (T));
using value_type = T;
static constexpr size_t dimension = S;
static constexpr size_t elements = S;
static constexpr std::size_t dimension = S;
static constexpr std::size_t elements = S;
/// returns the number of elements we contain
static constexpr auto size (void) { return S; }
// constructors
using init<S,T,SelfT>::init;
/// constructs, but does not initialise, the data.
///
/// used to avoid unnecessary initialisation in many situations where
/// we have arrays of these types that are about to be overwritten. it
/// is a very important performance optimisation.
base () = default;
constexpr explicit base (T val)
{ std::fill (begin (), end (), val); }
/// constructs an instance where all elements are initialised to `val'.
constexpr explicit
base (T fill)
{
for (decltype(S) i = 0; i < S; ++i)
this->data[i] = fill;
}
constexpr base (const base<S,T,SelfT> &rhs) = default;
base& operator= (const base<S,T,SelfT> &rhs) = default;
@ -85,7 +98,7 @@ namespace util::coord {
///////////////////////////////////////////////////////////////////////
// conversions
template <template <size_t, typename> class K>
template <template <std::size_t, typename> class K>
K<S,T> as (void) const
{
K<S,T> k;
@ -122,7 +135,11 @@ namespace util::coord {
}
///////////////////////////////////////////////////////////////////////
// redimension
/// returns an instance with the same data, but truncated to `D'
/// elements
///
/// explicitly does not allow a fill parameter given it can't be used
/// when reducing dimensions.
template <
size_t D,
typename _sfinae = SelfT
@ -143,6 +160,12 @@ namespace util::coord {
//---------------------------------------------------------------------
/// returns an instance with the same data, but more elements, where
/// the new elements are initialised with values with the same index
/// in the coordinate `fill'.
///
/// explicitly requires a fill parameter so that we avoid undefined
/// values.
template<size_t D,typename _sfinae = SelfT>
std::enable_if_t<
has_redim_v<_sfinae>,
@ -152,20 +175,17 @@ namespace util::coord {
{
redim_t<SelfT,D> out;
static constexpr auto L1 = min (S, D);
static constexpr auto L2 = D - L1;
std::copy_n (std::cbegin (this->data),
L1,
std::begin (out.data));
std::copy_n (fill.data + L1,
L2,
out.data + L1);
auto next = std::copy (cbegin (), cend (), std::begin (out));
std::copy (std::cbegin (fill) + S, std::cend (fill), next);
return out;
}
//---------------------------------------------------------------------
/// returns an instance with the same data, but more elements, where
/// all the new elemenst are initialised with the scalar `fill'.
///
/// explicitly requires a fill parameter so that we avoid undefined
/// values.
template <
size_t D,
typename _sfinae = SelfT
@ -178,16 +198,32 @@ namespace util::coord {
{
redim_t<SelfT,D> out;
auto cursor = std::copy_n (std::cbegin (this->data),
min (S, D),
std::begin (out.data));
std::fill (cursor, std::end (out.data), fill);
auto next = std::copy (cbegin (), cend (), std::begin (out));
std::fill (next, std::end (out), fill);
return out;
}
///////////////////////////////////////////////////////////////////////
/// returns an instance with elements specified by the Indices
/// parameter. eg, point2f p{}.indices<0,2> would return {p.x, p.z}.
///
/// it's ugly as sin, but simplifies some situations where we don't
/// want a temporary.
template <std::size_t ...Indices>
constexpr auto
indices (void) const
{
static_assert (
all (make_vector ((Indices < S)...)),
"indices must fall within the defined range for the type"
);
return redim_t<SelfT,sizeof...(Indices)> {
this->data[Indices]...
};
}
};
}
#include "ops.hpp"
#endif

View File

@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
* Copyright 2016-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_COORD_FWD_HPP

View File

@ -14,12 +14,12 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_COORD_INIT_HPP
#define __UTIL_COORD_INIT_HPP
#ifndef CRUFT_UTIL_COORD_INIT_HPP
#define CRUFT_UTIL_COORD_INIT_HPP
#include "store.hpp"
#include <cstdlib>
#include <cstddef>
namespace util::coord {
template <size_t S, typename T, typename SelfT>

View File

@ -11,14 +11,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
* Copyright 2016-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_IOSTREAM
#define __UTIL_IOSTREAM
#ifndef CRUFT_UTIL_IOSTREAM
#define CRUFT_UTIL_IOSTREAM
#include "../iterator.hpp"
#include <cstddef>
#include <ostream>
#include <algorithm>
@ -40,7 +41,6 @@ namespace util {
return os;
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -14,8 +14,8 @@
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_COORD_STORE_HPP
#define __UTIL_COORD_STORE_HPP
#ifndef CRUFT_UTIL_COORD_STORE_HPP
#define CRUFT_UTIL_COORD_STORE_HPP
#include "fwd.hpp"
@ -32,8 +32,8 @@
namespace util::coord::detail {
template <typename T>
constexpr
size_t
alignment (size_t S)
std::size_t
alignment (std::size_t S)
{
(void)S;
@ -76,9 +76,42 @@ namespace util::coord { \
}
#define DEFINE_STORE(KLASS,...) \
template <typename T> \
struct util::coord::store< \
VA_ARGS_COUNT(__VA_ARGS__), \
T, \
::util::KLASS< \
VA_ARGS_COUNT(__VA_ARGS__), \
T \
> \
> { \
union { \
T data[VA_ARGS_COUNT(__VA_ARGS__)]; \
struct { T __VA_ARGS__; }; \
}; \
};
DEFINE_STORE(extent,w)
DEFINE_STORE(extent,w,h)
DEFINE_STORE(extent,w,h,d)
DEFINE_STORE(point, x)
DEFINE_STORE(point, x, y)
DEFINE_STORE(point, x, y, z)
DEFINE_STORE(point, x, y, z, w)
DEFINE_STORE(vector, x)
DEFINE_STORE(vector, x, y)
DEFINE_STORE(vector, x, y, z)
DEFINE_STORE(vector, x, y, z, w)
#undef DEFINE_STORE
#if 0
template <typename T>
struct util::coord::store<1,T,::util::extent<1,T>> {
union { struct { T w; }; T data[1]; };
union { T data[1]; struct { T w; }; };
};
template <typename T>
@ -130,5 +163,5 @@ template <typename T>
struct util::coord::store<4,T,::util::vector<4,T>> {
union { struct { T x, y, z, w; }; T data[4]; };
};
#endif
#endif

24
crypto/salsa.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "./salsa.hpp"
///////////////////////////////////////////////////////////////////////////////
std::array<uint8_t,64>
util::crypto::salsa20 (const std::array<uint8_t,64> bytes) noexcept
{
auto x = *reinterpret_cast<const std::array<uint32_t,16>*> (&bytes);
auto y = x;
for (auto &t: x)
t = util::ltoh (t);
for (int i = 0; i < 10; ++i)
x = salsa::doubleround (x);
for (size_t i = 0; i < std::size (y); ++i)
x[i] += y[i];
for (auto &t: x)
t = util::htol (t);
return *reinterpret_cast<std::array<uint8_t,64>*> (&x);
}

86
crypto/salsa.hpp Normal file
View File

@ -0,0 +1,86 @@
#include <cstdint>
#include <array>
#include "../bitwise.hpp"
#include "../endian.hpp"
namespace util::crypto::salsa {
///////////////////////////////////////////////////////////////////////////
constexpr
uint32_t
R (uint32_t a, uint32_t b, uint32_t c, uint32_t k)
{
return b ^ util::rotatel (a + c, k);
}
///////////////////////////////////////////////////////////////////////////
constexpr
std::array<uint32_t,4>
quarter (std::array<uint32_t,4> y) noexcept
{
std::array<uint32_t,4> z {};
z[1] = R (y[0], y[1], y[3], 7);
z[2] = R (z[1], y[2], y[0], 9);
z[3] = R (z[2], y[3], z[1], 13);
z[0] = R (z[3], y[0], z[2], 18);
return z;
}
///////////////////////////////////////////////////////////////////////////
constexpr
std::array<uint32_t,16>
row (const std::array<uint32_t,16> y) noexcept
{
const auto [z00, z01, z02, z03] = quarter ({y[ 0], y[ 1], y[ 2], y[ 3]});
const auto [z05, z06, z07, z04] = quarter ({y[ 5], y[ 6], y[ 7], y[ 4]});
const auto [z10, z11, z08, z09] = quarter ({y[10], y[11], y[ 8], y[ 9]});
const auto [z15, z12, z13, z14] = quarter ({y[15], y[12], y[13], y[14]});
return {
z00, z01, z02, z03,
z04, z05, z06, z07,
z08, z09, z10, z11,
z12, z13, z14, z15
};
}
///////////////////////////////////////////////////////////////////////////
constexpr
std::array<uint32_t,16>
col (const std::array<uint32_t,16> x) noexcept
{
const auto [y00, y04, y08, y12] = quarter ({x[ 0], x[ 4], x[ 8], x[12]});
const auto [y05, y09, y13, y01] = quarter ({x[ 5], x[ 9], x[13], x[ 1]});
const auto [y10, y14, y02, y06] = quarter ({x[10], x[14], x[ 2], x[ 6]});
const auto [y15, y03, y07, y11] = quarter ({x[15], x[ 3], x[ 7], x[11]});
return {
y00, y01, y02, y03,
y04, y05, y06, y07,
y08, y09, y10, y11,
y12, y13, y14, y15,
};
}
///////////////////////////////////////////////////////////////////////////
constexpr
std::array<uint32_t,16>
doubleround (const std::array<uint32_t,16> x) noexcept
{
return row (col (x));
}
}
namespace util::crypto {
///////////////////////////////////////////////////////////////////////////
std::array<uint8_t,64>
salsa20 (const std::array<uint8_t,64>) noexcept;
}

View File

@ -26,7 +26,7 @@ using namespace util::debug;
////////////////////////////////////////////////////////////////////////////////
void
detail::panic (const char *msg)
util::debug::detail::panic (const char *msg)
{
std::cerr << "PANIC: " << msg << "\n" << ::debug::backtrace () << std::endl;
breakpoint ();
@ -36,7 +36,7 @@ detail::panic (const char *msg)
////////////////////////////////////////////////////////////////////////////////
void
detail::not_implemented (const char *msg)
util::debug::detail::not_implemented (const char *msg)
{
panic (msg);
}
@ -44,7 +44,7 @@ detail::not_implemented (const char *msg)
//-----------------------------------------------------------------------------
void
detail::unreachable (const char *msg)
util::debug::detail::unreachable (const char *msg)
{
panic (msg);
}

View File

@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2010-2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2010-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __DEBUG_HPP
@ -24,13 +24,22 @@
///////////////////////////////////////////////////////////////////////////////
// it is fractionally easier to define a constexpr variable which can be used
// in constexpr-if to enable/disable some codepaths rather than deal with
// macros in some scenarios. eg, templates are complicated enough without
// (more) macros.
#if !defined(NDEBUG)
#define DEBUG_ONLY(X) do { X } while (0)
constexpr bool debug_enabled = true;
#else
#define DEBUG_ONLY(X) do { } while (0)
constexpr bool debug_enabled = false;
#endif
///----------------------------------------------------------------------------
/// enable some code only if assertions et al are enabled
#define DEBUG_ONLY(X) do { if constexpr (debug_enabled) { X } } while (0)
///////////////////////////////////////////////////////////////////////////////
#define EXIT_XSUCCESS 0
#define EXIT_XSKIP 77
@ -221,8 +230,9 @@
#define CHECK_NEZ(A) do { \
DEBUG_ONLY ( \
const auto &__a = (A); \
\
if (::util::exactly_zero (__a)) \
_CHECK_PANIC ("expected zero\n" \
_CHECK_PANIC ("expected non-zero\n" \
"__a: %s is %!", \
#A, __a); \
); \
@ -234,6 +244,7 @@
DEBUG_ONLY ( \
const auto &__check_mod_v = (V); \
const auto &__check_mod_m = (M); \
\
if (!::util::exactly_zero (__check_mod_v % __check_mod_m)) \
_CHECK_PANIC ("expected zero modulus\n" \
"__v: %s is %!\n" \
@ -296,6 +307,70 @@
} while (0)
///////////////////////////////////////////////////////////////////////////////
/// make the compiler think a particular variable may now be aliased somewhere.
///
/// useful for preventing optimisations eliding a variable.
///
/// stolen from Chandler Carruth's 2015 talk: "Tuning C++".
namespace util::debug {
template <class T>
inline T*
escape (T *t)
{
asm volatile ("": : "g"(t): "memory");
return t;
}
template <class T>
inline const T*
escape (const T *t)
{
asm volatile ("": : "g"(t): "memory");
return t;
}
template <class T>
inline const T&
escape (const T &t)
{
return *escape (&t);
}
template <class T>
inline T&
escape (T &t)
{
return *escape (&t);
}
template <typename T, typename ...Args>
inline void
escape (T t, Args ...args)
{
escape (t);
escape (args...);
}
}
///////////////////////////////////////////////////////////////////////////////
/// force the compiler to conceptually dirty the global memory space.
///
/// stolen from Chandler Carruth's 2015 talk: "Tuning C++".
namespace util::debug {
inline void
clobber (void)
{
asm volatile ("": : : "memory");
}
}
///////////////////////////////////////////////////////////////////////////////
constexpr void panic [[noreturn]] (const char*);
@ -317,6 +392,17 @@ constexpr void unreachable [[noreturn]] (void);
constexpr void unreachable [[noreturn]] (const char*);
///////////////////////////////////////////////////////////////////////////////
/// report a fatal error induced by an unhandled value, especially in switch
/// statements. will almost invariably abort the application.
template <typename T>
constexpr void
unhandled [[noreturn]] (T &&t) noexcept
{
panic ("unhandled value %!", std::forward<T> (t));
}
///////////////////////////////////////////////////////////////////////////////
void warn (void);
void warn (const std::string&);

View File

@ -33,7 +33,7 @@ namespace util {
//-------------------------------------------------------------------------
template <typename T>
constexpr T
bswap (T);
bswap (T) noexcept;
// CXX: Update using "if constexpr" when available. It doesn't seem to be
// worth the dicking about to use enable_if_t to differentiate the
@ -42,7 +42,7 @@ namespace util {
template <> \
constexpr \
int##S##_t \
bswap (int##S##_t v) { \
bswap (int##S##_t v) noexcept { \
const union { \
int##S##_t s; \
uint##S##_t u; \
@ -55,12 +55,31 @@ namespace util {
SIGNED_BSWAP(32)
SIGNED_BSWAP(64)
template <> constexpr int8_t bswap ( int8_t v) { return v; }
template <> constexpr uint8_t bswap (uint8_t v) { return v; }
template <> constexpr int8_t bswap ( int8_t v) noexcept { return v; }
template <> constexpr uint8_t bswap (uint8_t v) noexcept { return v; }
template <> constexpr uint16_t bswap (uint16_t v) { return __builtin_bswap16 (v); }
template <> constexpr uint32_t bswap (uint32_t v) { return __builtin_bswap32 (v); }
template <> constexpr uint64_t bswap (uint64_t v) { return __builtin_bswap64 (v); }
template <> constexpr uint16_t bswap (uint16_t v) noexcept { return __builtin_bswap16 (v); }
template <> constexpr uint32_t bswap (uint32_t v) noexcept { return __builtin_bswap32 (v); }
template <> constexpr uint64_t bswap (uint64_t v) noexcept { return __builtin_bswap64 (v); }
// use a type-punning union to punt the byte swapping operation to the
// unsigned integer code.
//
// this is debatably safe under production compilers like gcc + clang
// despite what the standard may say about unions.
template <>
constexpr float
bswap (float v) noexcept
{
union {
float f;
uint32_t u;
} temp { .f = v };
temp.u = bswap (temp.u);
return temp.f;
}
//-------------------------------------------------------------------------

View File

@ -98,7 +98,7 @@ template <size_t S, typename T>
typename extent_range<S,T>::iterator
extent_range<S,T>::begin (void) const
{
return iterator (m_target, util::point<S,T> (0));
return { m_target, util::point<S,T> (0) };
}
@ -110,7 +110,7 @@ extent_range<S,T>::end (void) const
util::point<S,T> cursor (0);
cursor[S-1] = m_target[S-1];
return iterator (m_target, cursor);
return { m_target, cursor };
}

View File

@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2010-2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2010-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_EXTENT_HPP
@ -43,8 +43,25 @@ namespace util {
constexpr
U aspect (void) const;
template <typename U>
bool includes (::util::point<S,U>) const;
/// tests whether a point would lie within:
/// region { origin, *this }, inclusive of borders.
///
/// included for parity with util::region.
constexpr bool
inclusive (util::point<S,T> p) const
{
return all (p >= T{0} && p <= *this);
}
/// tests whether a point would like within:
/// region { origin, *this }, exclusive of the bottom-right border
/// included for parity with util::region
constexpr bool
exclusive (point<S,T> p) const
{
return all (p >= T{0} && p < *this);
}
::util::extent<S,T> expanded (::util::vector<S,T>) const;
::util::extent<S,T> expanded (T) const;
@ -79,7 +96,7 @@ namespace util {
extent<S,T> m_target;
};
extent_range (extent<S,T> target);
explicit extent_range (extent<S,T> target);
iterator begin (void) const;
iterator end (void) const;
@ -88,6 +105,17 @@ namespace util {
extent<S,T> m_target;
};
///////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
extent_range<S,T>
make_range (extent<S,T> e)
{
return extent_range<S,T> {e};
}
///////////////////////////////////////////////////////////////////////////
// convenience typedefs
template <typename T> using extent2 = extent<2,T>;
template <typename T> using extent3 = extent<3,T>;
@ -97,20 +125,24 @@ namespace util {
template <size_t S> using extentf = extent<S,float>;
template <size_t S> using extentd = extent<S,double>;
typedef extent2<int> extent2i;
typedef extent2<unsigned> extent2u;
typedef extent2<float> extent2f;
typedef extent2<double> extent2d;
typedef extent3<unsigned> extent3u;
typedef extent3<float> extent3f;
//-------------------------------------------------------------------------
template <typename T> using extent_range2 = extent_range<2,T>;
template <typename T> using extent_range3 = extent_range<3,T>;
using extent_range2u = extent_range2<typename extent2u::value_type>;
using extent_range2i = extent_range2<typename extent2i::value_type>;
using extent_range3u = extent_range2<typename extent3u::value_type>;
}

View File

@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
*/
@ -66,19 +66,6 @@ util::extent<S,T>::aspect (void) const
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
template <typename U>
bool
util::extent<S,T>::includes (point<S,U> p) const
{
for (size_t i = 0; i < S; ++i)
if (p[i] < 0 || static_cast<T> (p[i]) >= this->data[i])
return false;
return true;
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
constexpr

View File

@ -60,7 +60,7 @@ namespace util::format::detail {
//
// other values are theoretically supportable, but do not form part of
// the printf specification.
unsigned base = 10;
int base = 10;
enum class repr {
FIXED,
@ -81,7 +81,7 @@ namespace util::format::detail {
OSTREAM
} k;
unsigned width = 0; // field width, ie: how many characters
int width = 0; // field width, ie: how many characters
int precision = -1; // how many digits after the decimal
size_t length = 0; // bytesize of underlying type
@ -619,7 +619,7 @@ namespace util::format::detail {
const auto len = spec.precision < 0 ? spec.precision :
(size_t)spec.precision < strlen (t) ? spec.precision :
strlen (t);
(int)strlen (t);
// perform left padding
if (spec.width > len && !spec.left_adjusted)
@ -788,7 +788,7 @@ namespace util::format::detail {
"0123456789abcdef";
char buffer[numerals];
size_t remain = numerals;
auto remain = numerals;
for (auto cursor = buffer; remain--; t /= spec.base)
*cursor++ = NUMERALS[t % spec.base];

View File

@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
*/
@ -21,11 +21,12 @@
#include "../coord/iostream.hpp"
#include "../debug.hpp"
using util::geom::AABB;
using util::geom::aabb;
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
AABB<S,T>::AABB (point<S,T> _p0, point<S,T> _p1):
aabb<S,T>::aabb (const point<S,T> _p0, const point<S,T> _p1):
p0 (_p0),
p1 (_p1)
{
@ -33,10 +34,10 @@ AABB<S,T>::AABB (point<S,T> _p0, point<S,T> _p1):
}
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
T
AABB<S,T>::diameter (void) const
aabb<S,T>::diameter (void) const
{
return magnitude ().diameter ();
}
@ -45,48 +46,25 @@ AABB<S,T>::diameter (void) const
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::extent<S,T>
AABB<S,T>::magnitude (void) const
aabb<S,T>::magnitude (void) const
{
extent<S,T> out;
for (size_t i = 0; i < S; ++i)
out[i] = p1[i] - p0[i];
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
bool
AABB<S,T>::overlaps (point<S,T> p) const
{
for (size_t i = 0; i < S; ++i)
if (p0[i] > p[i] || p1[i] < p[i])
return false;
return true;
return (p1 - p0).template as<util::extent> ();
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::point<S,T>
AABB<S,T>::closest (point<S,T> q) const
aabb<S,T>::closest (const point<S,T> q) const
{
point<S,T> res;
for (size_t i = 0; i < S; ++i)
res[i] = q[i] < p0[i] ? p0[i] :
q[i] > p1[i] ? p1[i] :
q[i];
return res;
return limit (q, p0, p1);
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
void
AABB<S,T>::cover (point<S,T> p)
aabb<S,T>::cover (const point<S,T> p)
{
p0 = min (p, p0);
p1 = max (p, p1);
@ -95,8 +73,8 @@ AABB<S,T>::cover (point<S,T> p)
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
AABB<S,T>
AABB<S,T>::operator+ (vector<S,T> v) const
aabb<S,T>
aabb<S,T>::operator+ (const vector<S,T> v) const
{
return { p0 + v, p1 + v };
}
@ -104,34 +82,20 @@ AABB<S,T>::operator+ (vector<S,T> v) const
//-----------------------------------------------------------------------------
template <size_t S, typename T>
AABB<S,T>
AABB<S,T>::operator- (vector<S,T> v) const
aabb<S,T>
aabb<S,T>::operator- (const vector<S,T> v) const
{
return { p0 - v, p1 - v };
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
bool
AABB<S,T>::operator== (const AABB<S,T> rhs) const
{
return rhs.p0 == p0 && rhs.p1 == p1;
}
//-----------------------------------------------------------------------------
namespace util::debug {
template <size_t S, typename T>
struct validator<AABB<S,T>> {
static bool is_valid (const AABB<S,T> &b)
struct validator<aabb<S,T>> {
static bool is_valid (const aabb<S,T> &b)
{
for (size_t i = 0; i < S; ++i)
if (b.p1[i] < b.p0[i])
return false;
return true;
return all (b.p0 <= b.p1);
}
};
}
@ -140,18 +104,17 @@ namespace util::debug {
//-----------------------------------------------------------------------------
template <size_t S, typename T>
std::ostream&
util::geom::operator<< (std::ostream &os, util::geom::AABB<S,T> b)
util::geom::operator<< (std::ostream &os, util::geom::aabb<S,T> b)
{
os << "AABB(" << b.p0 << ", " << b.p1 << ")";
return os;
return os << "[ " << b.p0 << ", " << b.p1 << " ]";
}
//-----------------------------------------------------------------------------
#define INSTANTIATE_S_T(S,T) \
namespace util::geom { template struct AABB<S,T>; } \
template bool util::debug::is_valid (const AABB<S,T>&); \
template std::ostream& util::geom::operator<< (std::ostream&, AABB<S,T>);
namespace util::geom { template struct aabb<S,T>; } \
template bool util::debug::is_valid (const aabb<S,T>&); \
template std::ostream& util::geom::operator<< (std::ostream&, aabb<S,T>);
#define INSTANTIATE(T) \
INSTANTIATE_S_T(2,T) \

View File

@ -11,12 +11,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015-2016 Danny Robson <danny@nerdcruft.net>
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_GEOM_AABB_HPP
#define __UTIL_GEOM_AABB_HPP
#ifndef CRUFT_UTIL_GEOM_AABB_HPP
#define CRUFT_UTIL_GEOM_AABB_HPP
#include "../point.hpp"
#include "../extent.hpp"
@ -24,38 +24,75 @@
#include <cstdint>
namespace util::geom {
///////////////////////////////////////////////////////////////////////////
/// represents an axis-aligned bounding-box through two opposing corners.
///
/// p0 must be less-than-or-equal to p1. equality is allowed so that we
/// can represent zero sized bounding-boxes.
template <size_t S, typename T>
struct AABB {
AABB () = default;
AABB (point<S,T>, point<S,T>);
struct aabb {
aabb () = default;
aabb (point<S,T>, point<S,T>);
T diameter (void) const;
extent<S,T> magnitude (void) const;
T diameter (void) const;
bool overlaps (point<S,T>) const;
/// tests whether a point lies within the region, inclusive of borders
constexpr bool
inclusive (point<S,T> p) const noexcept
{ return all (p0 <= p && p1 >= p); }
point<S,T> closest (point<S,T>) const;
void cover (point<S,T>);
AABB<S,T> operator+ (vector<S,T>) const;
AABB<S,T> operator- (vector<S,T>) const;
bool operator== (AABB) const;
aabb<S,T> operator+ (vector<S,T>) const;
aabb<S,T> operator- (vector<S,T>) const;
::util::point<S,T> p0;
::util::point<S,T> p1;
};
typedef AABB<2,float> AABB2f;
typedef AABB<2,unsigned> AABB2u;
typedef AABB<2,int> AABB2i;
typedef AABB<3,float> AABB3f;
typedef AABB<3,unsigned> AABB3u;
typedef AABB<3,int> AABB3i;
///////////////////////////////////////////////////////////////////////////
template <std::size_t S, typename T>
constexpr bool
operator== (const aabb<S,T> &a, const aabb<S,T> &b) noexcept
{
return a.p0 == b.p0 && a.p1 == b.p1;
}
///////////////////////////////////////////////////////////////////////////
typedef aabb<2,float> aabb2f;
typedef aabb<2,unsigned> aabb2u;
typedef aabb<2,int> aabb2i;
typedef aabb<3,float> aabb3f;
typedef aabb<3,unsigned> aabb3u;
typedef aabb<3,int> aabb3i;
}
#include "aabb.ipp"
///////////////////////////////////////////////////////////////////////////////
#include "./sample.hpp"
#include <random>
namespace util::geom {
template <size_t S, typename T, typename G>
struct sampler<S,T,aabb,G> {
static point<S,T>
fn (aabb<S,T> b, G &g)
{
std::uniform_real_distribution<T> d;
point<S,T> p;
std::generate (p.begin (), p.end (), [&] (void) { return d (g); });
return p * (b.p1 - b.p0) + b.p0.template as<util::vector> ();
}
};
}
#endif

View File

@ -1,43 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#if defined(__UTIL_GEOM_AABB_IPP)
#error
#endif
#define __UTIL_GEOM_AABB_IPP
#include "sample.hpp"
#include <random>
///////////////////////////////////////////////////////////////////////////////
namespace util::geom {
template <size_t S, typename T, typename G>
struct sampler<S,T,AABB,G> {
static point<S,T>
fn (AABB<S,T> b, G &g)
{
std::uniform_real_distribution<T> d;
point<S,T> p;
std::generate (p.begin (), p.end (), [&] (void) { return d (g); });
return p * (b.p1 - b.p0) + b.p0.template as<util::vector> ();
}
};
}

View File

@ -11,12 +11,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
*/
#include "ellipse.hpp"
#include "./ellipse.hpp"
#include "ops.hpp"
#include "./ops.hpp"
#include "./aabb.hpp"
using util::geom::ellipse;
@ -47,7 +48,7 @@ template bool util::geom::intersects (ellipse<3,float>, util::point<3,float>);
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
static util::geom::AABB<S,T>
static util::geom::aabb<S,T>
bounds (ellipse<S,T> e)
{
return {
@ -59,7 +60,7 @@ bounds (ellipse<S,T> e)
//-----------------------------------------------------------------------------
template <size_t S, typename T, template <size_t,typename> class K>
util::geom::AABB<S,T>
util::geom::aabb<S,T>
util::geom::bounds (K<S,T> k)
{
return ::bounds (k);
@ -67,5 +68,5 @@ util::geom::bounds (K<S,T> k)
//-----------------------------------------------------------------------------
template util::geom::AABB<2,float> util::geom::bounds (ellipse<2,float>);
template util::geom::AABB<3,float> util::geom::bounds (ellipse<3,float>);
template util::geom::aabb<2,float> util::geom::bounds (ellipse<2,float>);
template util::geom::aabb<3,float> util::geom::bounds (ellipse<3,float>);

View File

@ -22,7 +22,7 @@
namespace util::geom {
template <size_t S, typename T> struct ray;
template <size_t S, typename T> struct plane;
template <size_t S, typename T> struct AABB;
template <size_t S, typename T> struct aabb;
template <size_t S, typename T> struct sphere;
template <size_t S, typename T> struct ellipse;
template <size_t S, typename T> struct rect;

View File

@ -26,7 +26,7 @@
namespace util::geom {
template <size_t S, typename T>
std::ostream&
operator<< (std::ostream&, AABB<S,T>);
operator<< (std::ostream&, aabb<S,T>);
template <size_t S, typename T>
std::ostream&

View File

@ -17,7 +17,7 @@
#ifndef __UTIL_GEOM_OPS_HPP
#define __UTIL_GEOM_OPS_HPP
#include "aabb.hpp"
#include "./fwd.hpp"
#include "../point.hpp"
@ -55,7 +55,7 @@ namespace util::geom {
typename T,
template <size_t,typename> class K
>
AABB<S,T>
aabb<S,T>
bounds (K<S,T>);
template <

View File

@ -24,30 +24,6 @@
using util::geom::ray;
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
ray<S,T>::ray (util::point<S,T> _origin,
util::vector<S,T> _direction):
origin (_origin),
direction (_direction)
{
CHECK (is_normalised (direction));
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
ray<S,T>
ray<S,T>::make (util::point<S,T> origin,
util::point<S,T> target)
{
return {
origin,
normalised (target - origin)
};
}
///////////////////////////////////////////////////////////////////////////////
/// returns the distance along the ray in a ray-plane intersection
///
@ -68,7 +44,7 @@ ray<S,T>::intersect (plane<S,T> q) const
/// returns NaN if behind
template <size_t S, typename T>
T
ray<S,T>::intersect (AABB<S,T> r) const
ray<S,T>::intersect (aabb<S,T> r) const
{
auto t1 = (r.p0 - origin) / direction;
auto t2 = (r.p1 - origin) / direction;

View File

@ -28,16 +28,26 @@
namespace util::geom {
template <size_t S, typename T>
struct ray {
ray (point<S,T> origin,
vector<S,T> direction);
constexpr ray () = default;
static
ray<S,T> make (point<S,T> origin,
point<S,T> target);
constexpr ray (point<S,T> _origin, vector<S,T> _direction) noexcept:
origin (_origin),
direction (_direction)
{
CHECK (is_normalised (direction));
}
constexpr ray (point<S,T> _origin, point <S,T> _distant) noexcept:
ray (_origin, _origin.to (_distant ))
{
CHECK (is_normalised (direction));
}
//---------------------------------------------------------------------
// intersection tests
T intersect (plane<S,T>) const;
T intersect (AABB<S,T>) const;
T intersect (aabb<S,T>) const;
T intersect (sphere<S,T>) const;
// queries
@ -50,6 +60,20 @@ namespace util::geom {
vector<S,T> direction;
};
template <std::size_t S, typename T>
constexpr auto
make_ray (point<S,T> p, vector<S,T> d) noexcept
{
return ray<S,T> { p, d };
}
template <std::size_t S, typename T>
constexpr auto
make_ray (point<S,T> p, point<S,T> q)
{
return ray<S,T> { p, q };
};
typedef ray<2,float> ray2f;
typedef ray<3,float> ray3f;
}

View File

@ -11,17 +11,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_GEOM_SAMPLE_HPP
#define __UTIL_GEOM_SAMPLE_HPP
#include "../point.hpp"
#include "../coord/fwd.hpp"
#include "./ops.hpp"
#include <cstddef>
///////////////////////////////////////////////////////////////////////////////
namespace util::geom {
/// a function object that selects a uniformly random point inside a shape
/// using a provided random generator. the point will lie within the shape,
/// inclusive of boundaries.
///
/// may be specialised for arbitrary shapes but uses rejection sampling
/// as a safe default. this implies that execution may not take a constant
/// time.
///
/// \tparam S coordinate type dimension
/// \tparam T value type for the shape/coordinate
/// \tparam K the shape type to test
/// \tparam G a UniformRandomBitGenerator, eg std::min19937
template <
size_t S,
typename T,
@ -29,9 +44,23 @@ namespace util::geom {
typename G
>
struct sampler {
static point<S,T> fn (K<S,T>, G&);
static point<S,T>
fn (K<S,T> k, G &g)
{
auto b = bounds (k);
while (true) {
auto p = sample (b, g);
if (intersects (k, p))
return p;
}
}
};
///////////////////////////////////////////////////////////////////////////
/// a convenience function that calls sample::fn to select a random point
/// in a provided shape.
template <
size_t S,
typename T,
@ -45,6 +74,4 @@ namespace util::geom {
}
}
#include "sample.ipp"
#endif

View File

@ -23,16 +23,17 @@
#include <array>
#include <cstddef>
#include <cstdint>
#include <experimental/filesystem>
#include <ostream>
#include <string>
#include <tuple>
#include <utility>
#include <experimental/filesystem>
namespace util {
// XXX: clang-3.9/clang-4.0 will not instantiate static constexpr member
// variables from class specialisations, so we have to use detail classes
// to hold the variables and instantiate _those_ members instead.
// clang#18781: clang-3.9/clang-4.0 will not instantiate static constexpr
// member variables from class specialisations, so we have to use detail
// classes to hold the variables and instantiate _those_ members instead.
template <typename T>
struct type_name;
@ -173,7 +174,7 @@ namespace util {
const char*, \
util::enum_traits<::NS::E>::value_count \
> PASTE(util::__enum_traits_,E)::names = { \
MAP(STRINGIZE_LIST, __VA_ARGS__) \
MAP0(STRINGIZE_LIST, __VA_ARGS__) \
};

36
io.cpp
View File

@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2010-2016 Danny Robson <danny@nerdcruft.net>
* Copyright 2010-2017 Danny Robson <danny@nerdcruft.net>
*/
#include "io.hpp"
@ -32,10 +32,15 @@
using namespace util;
//----------------------------------------------------------------------------
std::vector<char>
//////////////////////////////////////////////////////////////////////////////
template <typename T>
std::vector<T>
util::slurp (const std::experimental::filesystem::path &path)
{
static_assert (
sizeof (T) == 1,
"slurp is designed for grabbing bytes, not complex structures"
);
posix::fd out (path, O_RDONLY | O_BINARY);
// Calculate the total file size
@ -47,11 +52,11 @@ util::slurp (const std::experimental::filesystem::path &path)
throw errno_error ();
// Allocate a buffer, and keep reading until it's full.
std::vector<char> buffer (size);
std::vector<T> buffer (size);
CHECK_GE (size, 0);
size_t remaining = (size_t)size;
char *cursor = buffer.data ();
T *cursor = buffer.data ();
while (remaining) {
ssize_t consumed = ::read (out, cursor, remaining);
@ -69,9 +74,20 @@ util::slurp (const std::experimental::filesystem::path &path)
//-----------------------------------------------------------------------------
std::vector<char>
template std::vector<char> util::slurp (const std::experimental::filesystem::path&);
template std::vector<std::byte> util::slurp (const std::experimental::filesystem::path&);
///////////////////////////////////////////////////////////////////////////////
template <typename T>
std::vector<T>
util::slurp (FILE *stream)
{
static_assert (
sizeof (T) == 1,
"slurp is designed for grabbing bytes, not complex structures"
);
// find how much data is in this file
const int desc = fileno (stream);
if (desc < 0)
@ -81,7 +97,7 @@ util::slurp (FILE *stream)
if (fstat (desc, &meta) < 0)
errno_error::throw_code ();
std::vector<char> buf;
std::vector<T> buf;
// we think we know the size, so try to do a simple read
if (meta.st_size) {
@ -113,8 +129,12 @@ util::slurp (FILE *stream)
}
//-----------------------------------------------------------------------------
template std::vector<char> util::slurp (FILE*);
template std::vector<std::byte> util::slurp (FILE*);
///////////////////////////////////////////////////////////////////////////////
void
util::write (const posix::fd &out,
const void *restrict data,

10
io.hpp
View File

@ -20,8 +20,9 @@
#include "platform.hpp"
#include "posix/fd.hpp"
#include <cstdio>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <experimental/filesystem>
#include <vector>
#include <streambuf>
@ -35,8 +36,11 @@
namespace util {
//-------------------------------------------------------------------------
/// Reads an entire file into memory.
std::vector<char> slurp (const std::experimental::filesystem::path&);
std::vector<char> slurp (FILE *);
template <typename T = std::byte>
std::vector<T> slurp (const std::experimental::filesystem::path&);
template <typename T = std::byte>
std::vector<T> slurp (FILE *);
//-------------------------------------------------------------------------

View File

@ -27,7 +27,9 @@ using util::detail::posix::mapped_file;
//////////////////////////////////////////////////////////////////////////////
mapped_file::mapped_file (const std::experimental::filesystem::path &path, int fflags, int mflags):
mapped_file::mapped_file (const std::experimental::filesystem::path &path,
int fflags,
int mflags):
mapped_file (util::posix::fd (path, fflags), mflags)
{ ; }

View File

@ -31,8 +31,11 @@ namespace util {
namespace detail::posix {
class mapped_file {
public:
mapped_file (const std::experimental::filesystem::path&, int fflags = O_RDONLY | O_BINARY, int mflags = PROT_READ);
mapped_file (const util::posix::fd&, int mflags = PROT_READ);
mapped_file (const std::experimental::filesystem::path&,
int fflags = O_RDONLY | O_BINARY,
int mflags = PROT_READ);
mapped_file (const util::posix::fd&,
int mflags = PROT_READ);
mapped_file (const mapped_file&) = delete;
mapped_file& operator= (const mapped_file&) = delete;

View File

@ -20,6 +20,7 @@
#include "types/traits.hpp"
#include "variadic.hpp"
#include "view.hpp"
template <typename Base>
@ -71,6 +72,16 @@ class referencing_iterator {
namespace util {
///////////////////////////////////////////////////////////////////////////
/// an output iterator that inserts a delimiter between successive
/// assignments
///
/// very useful for outputting comma seperated lists to an ostream, eg:
///
/// std::copy (
/// std::cbegin (container),
/// std::cend (container),
/// util::infix_iterator<value_type> (os, ", ")
/// );
template <
typename T,
class CharT = char,
@ -110,6 +121,103 @@ namespace util {
};
namespace detail {
template <typename ContainerT, typename CharT>
struct infix_t {
const ContainerT &_container;
const CharT *_delimiter;
};
template <typename ContainerT, typename CharT>
std::ostream&
operator<< (std::ostream &os, const infix_t<ContainerT,CharT> &val)
{
std::copy (std::cbegin (val._container),
std::cend (val._container),
infix_iterator<typename ContainerT::value_type> (os, val._delimiter));
return os;
}
};
/// a helper function that returns an object that will use a
/// util::infix_iterator to output a container's values to an ostream with
/// the given delimiter.
///
/// reduces boilerplate code required to output lists of things
template <typename ContainerT, typename CharT = char>
auto
make_infix (const ContainerT &_container, const CharT *_delimiter = ", ")
{
return detail::infix_t<ContainerT,CharT> { _container, _delimiter };
};
///////////////////////////////////////////////////////////////////////////
//
template <typename IteratorT>
struct numeric_iterator : public std::iterator<
typename std::iterator_traits<IteratorT>::iterator_category,
decltype (+std::declval<typename std::iterator_traits<IteratorT>::value_type> ()),
typename std::iterator_traits<IteratorT>::difference_type,
typename std::iterator_traits<IteratorT>::pointer,
typename std::iterator_traits<IteratorT>::reference
> {
static_assert (std::is_arithmetic_v<typename std::iterator_traits<numeric_iterator>::value_type>);
explicit numeric_iterator (IteratorT _inner):
m_inner (_inner)
{ ; }
auto operator++ (void) { ++m_inner; return *this; }
auto
operator- (const numeric_iterator &rhs) const
{
return typename std::iterator_traits<IteratorT>::difference_type { m_inner - rhs.m_inner };
}
auto
operator* (void) const
{
return +*m_inner;
}
auto operator== (const numeric_iterator &rhs) const { return m_inner == rhs.m_inner; }
auto operator!= (const numeric_iterator &rhs) const { return m_inner != rhs.m_inner; }
private:
IteratorT m_inner;
};
//-------------------------------------------------------------------------
// convenience function that constructs a view of numeric_iterators for a
// provided container
template <typename ContainerT>
auto
numeric_view (ContainerT &data)
{
return util::view {
numeric_iterator (std::begin (data)),
numeric_iterator (std::end (data))
};
}
//-------------------------------------------------------------------------
template <typename ContainerT>
auto
numeric_view (const ContainerT &data)
{
return util::view {
numeric_iterator (std::begin (data)),
numeric_iterator (std::end (data))
};
}
///////////////////////////////////////////////////////////////////////////
template <typename ContainerT>
class indices {
@ -173,25 +281,31 @@ namespace util {
///////////////////////////////////////////////////////////////////////////
namespace detail::zip {
// holds a tuple of iterators for begin and end, and returns an
// iterator that transforms these iterators into tuples of value_types.
//
// this must be expressed in terms of iterators, rather than containers,
// because it dramatically simplifies iterating over raw arrays.
template <
typename ContainerT,
typename IteratorT,
typename I = std::make_index_sequence<std::tuple_size<ContainerT>::value>
typename I = std::make_index_sequence<std::tuple_size<IteratorT>::value>
>
struct collection;
class collection;
//---------------------------------------------------------------------
template <
typename ContainerT,
typename IteratorT,
std::size_t ...I
>
struct collection<
ContainerT,
class collection<
IteratorT,
std::index_sequence<I...>
> {
collection (const ContainerT &_containers):
m_containers { _containers }
public:
collection (const IteratorT &_begin, const IteratorT &_end):
m_begin { _begin },
m_end { _end }
{ ; }
struct iterator : std::iterator<
@ -203,13 +317,14 @@ namespace util {
>,
std::size_t
> {
IteratorT m_iterators;
iterator (IteratorT _iterators):
public:
iterator (const IteratorT &_iterators):
m_iterators (_iterators)
{ ; }
iterator& operator++ (void)
iterator&
operator++ (void)
{
// HACK: we don't actually need to create a tuple here,
// but it's a zero cost method to expand the parameter
@ -218,58 +333,86 @@ namespace util {
return *this;
}
iterator operator++ (int);
auto operator* (void)
auto
operator* (void)
{
return std::make_tuple (*std::get<I> (m_iterators)...);
}
bool operator== (const iterator &rhs) const
bool
operator== (const iterator &rhs) const
{
return m_iterators == rhs.m_iterators;
}
bool operator!= (const iterator &rhs) const
bool
operator!= (const iterator &rhs) const
{
return !(*this == rhs);
}
private:
IteratorT m_iterators;
};
iterator begin (void)
iterator
begin (void)
{
return iterator { { std::begin (std::get<I> (m_containers))... } };
return iterator { { std::get<I> (m_begin)... } };
}
iterator end (void)
iterator
end (void)
{
return iterator { { std::end (std::get<I> (m_containers))... } };
return iterator { { std::get<I> (m_end)... } };
}
ContainerT m_containers;
private:
IteratorT m_begin;
IteratorT m_end;
};
}
//-------------------------------------------------------------------------
///------------------------------------------------------------------------
/// takes a variable number of container arguments and returns an interable
/// object with a value_type of tuple of the argument's value_types.
///
/// the returned iterator value_type is suitable for using in range-for
/// and structured bindings (and really, that's the entire point here).
///
/// eg, util::zip ({1,2,3}, {4,5,6}) ~= {{1,4},{2,5},{3,6}}
template <typename ...ContainerT>
auto
zip (const ContainerT&... data)
{
using container = std::tuple<ContainerT...>;
using iterator = std::tuple<decltype(std::begin(data))...>;
using IteratorT = std::tuple<decltype(std::begin(data))...>;
return detail::zip::collection<
container,
iterator,
IteratorT,
std::make_index_sequence<sizeof...(ContainerT)>
> (
std::make_tuple (data...)
);
> {
std::make_tuple (std::begin (data)...),
std::make_tuple (std::end (data)...)
};
};
//-------------------------------------------------------------------------
///------------------------------------------------------------------------
/// takes a variable number of containers and returns a zipped iterable
/// object where the first of the iterator's value_types is the index of
/// that iterator. ie, it combines container offsets with value_types.
///
/// eg, util::izip ("abc") ~= {{0,'a'},{1,'b'},{2,'c'}}
template <typename ...ContainerT>
auto
izip (const ContainerT&... data)
@ -279,6 +422,22 @@ namespace util {
data...
);
}
}
///////////////////////////////////////////////////////////////////////////
/// an output iterator that always discards any parameters on assignment.
///
/// sometimes useful to pass to algorithms that generate useful results as
/// a return value, while not caring about the implicit OutputIterator
/// results.
struct discard_iterator : public std::iterator<std::output_iterator_tag, discard_iterator> {
template <typename T>
void operator= (const T&) { ; }
discard_iterator& operator++ ( ) { return *this; }
discard_iterator operator++ (int) { return *this; }
discard_iterator& operator* ( ) { return *this; }
};
};
#endif

84
job/queue.cpp Normal file
View File

@ -0,0 +1,84 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#include "./queue.hpp"
#include <iostream>
using util::job::queue;
///////////////////////////////////////////////////////////////////////////////
queue::queue ():
queue (std::thread::hardware_concurrency () ?: 1)
{ ; }
//-----------------------------------------------------------------------------
queue::queue (unsigned thread_count):
m_loop ([] (store &s) {
args obj;
while (true) {
// acquire the work lock and see if we need to quit, continue,
// or sleep
std::unique_lock<std::mutex> lk (s.mutex);
if (s.pending.empty ()) {
s.cv.wait (lk, [&] () {
return s.stopping.load () || !s.pending.empty ();
});
}
if (s.stopping.load ())
break;
// extract the arguments and forward them to the functor
obj = std::move (s.pending.front ());
s.pending.pop_front ();
lk.unlock ();
s.cv.notify_one ();
obj.function (obj);
}
}),
m_threads (thread_count)
{
for (auto &t: m_threads)
t = std::thread (m_loop, std::ref (m_store));
}
//-----------------------------------------------------------------------------
queue::~queue ()
{
// tell everyone we want to quit
{
std::lock_guard<std::mutex> lk {m_store.mutex};
m_store.stopping.store (true);
}
m_store.cv.notify_all ();
// wait for everyone to tidy up. perhaps we'd like to use a timeout, but
// if things deadlock then it's the users fault currently.
std::for_each (
std::begin (m_threads),
std::end (m_threads),
[] (auto &t)
{
t.join ();
});
}

154
job/queue.hpp Normal file
View File

@ -0,0 +1,154 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_JOB_QUEUE_HPP
#define CRUFT_UTIL_JOB_QUEUE_HPP
#include <array>
#include <deque>
#include <thread>
#include <vector>
#include <new>
#include <cstddef>
#include <functional>
#include <atomic>
#include <mutex>
#include <condition_variable>
namespace util::job {
class queue {
public:
queue ();
explicit queue (unsigned thread_count);
~queue ();
using cookie = int;
template <class Function, typename ...Args>
cookie
submit (cookie &parent, Function&&, Args&&...);
/// record a functor and a set of parameters to execute at some point
/// in the future by an arbitrary available thread.
template <class Function, typename ...Args>
cookie
submit (Function &&func, Args &&...params)
{
{
std::unique_lock<std::mutex> lk (m_store.mutex);
m_store.pending.emplace_back (
std::forward<Function> (func),
std::forward<Args> (params)...
);
}
m_store.cv.notify_one ();
// TODO: return a useful identifier to allow waiting
return 0;
}
void wait (cookie);
// HACK: this doesn't actually implement a proper barrier and may not
// even guarantee that all jobs are flushed. it's provided to make
// some amount of testing slightly more convenient by draining most
// of the queue on demand.
void
flush (void)
{
// setup a cv and completion flag. this is a poor man's barrier.
std::mutex m;
std::unique_lock<std::mutex> lk (m);
std::condition_variable cv;
std::atomic<bool> done = false;
// submit a job to the back of the queue that sets the done flag
// and wakes us back up again.
submit ([&] (void) {
{
std::lock_guard<std::mutex> _{m};
done.store (true);
}
cv.notify_one ();
});
// wait until the flag is set then exit.
do {
cv.wait (lk, [&] () { return done.load (); });
} while (!done.load ());
}
private:
/// stores a functor and associated arguments in a fixed size buffer
/// for later execution.
///
/// for ease of implementation the arguments are currently restricted
/// as follows:
/// * trivial types (memcpy'able)
/// * a fixed total maximum size of around one cache line
/// these limitations will be eliminated at some point in the future
///
/// the user supplied functor is wrapped with our own that unpacks and
/// forwards the arguments from the data buffer. this function must
/// be passed a copy of the current arg object as the only argument.
struct args {
args () = default;
template <class Function, typename ...Args>
args (Function &&func, Args&&...params)
{
using tuple_t = std::tuple<std::decay_t<Args>...>;
static_assert ((std::is_trivial_v<std::decay_t<decltype(params)>> && ...));
static_assert (sizeof (tuple_t) <= sizeof data);
union {
decltype(data) *byte_ptr;
tuple_t *args_ptr;
};
byte_ptr = &data;
*args_ptr = std::make_tuple (params...);
function = [func] (args &base) {
std::apply (func, *reinterpret_cast<tuple_t*> (&base.data));
};
};
// GCC: switch to hardware_destructive_interference_size when it
// becomes available in libstdc++. Until then we use a sensible
// guess.
std::array<char,64> data;
std::function<void(args&)> function;
};
struct store {
std::atomic<bool> stopping = false;
std::deque<args> pending;
std::condition_variable cv;
std::mutex mutex;
};
store m_store;
std::function<void(store&)> m_loop;
std::vector<std::thread> m_threads;
};
}
#endif

View File

@ -14,11 +14,12 @@
* You should have received a copy of the GNU General Public License
* along with libgim. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2010-2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2010-2017 Danny Robson <danny@nerdcruft.net>
*/
#include "json/flat.hpp"
#include "debug.hpp"
#include "json/except.hpp"
#include "preprocessor.hpp"
@ -171,9 +172,7 @@ template \
std::vector<json::flat::item<KLASS>> \
json::flat::parse (util::view<KLASS>);
MAP(
INSTANTIATE,
MAP0(INSTANTIATE,
std::string::iterator,
std::string::const_iterator,
const char* restrict,

View File

@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
*/
#include "schema.hpp"
@ -19,6 +19,7 @@
#include "tree.hpp"
#include "except.hpp"
#include "../debug.hpp"
#include "../io.hpp"
#include "../maths.hpp"

View File

@ -23,9 +23,10 @@
#include "../debug.hpp"
#include "../io.hpp"
#include "../maths.hpp"
#include "../preprocessor.hpp"
#include "../stream.hpp"
#include "preprocessor.hpp"
#include <algorithm>
#include <cstdlib>
#include <iomanip>
@ -226,9 +227,7 @@ template \
std::unique_ptr<json::tree::node> \
json::tree::parse (util::view<KLASS>);
MAP(
INSTANTIATE,
MAP0(INSTANTIATE,
std::string::iterator,
std::string::const_iterator,
const char* restrict,

94
json2/event.cpp Normal file
View File

@ -0,0 +1,94 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#include "./event.hpp"
#include "./except.hpp"
#include "../debug.hpp"
using util::json2::event::packet;
///////////////////////////////////////////////////////////////////////////////
util::json2::event::type_t
packet::type (void) const noexcept
{
CHECK_NEQ (first, last);
const auto &c = *first;
switch (c) {
case '{': return type_t::OBJECT_BEGIN;
case '}': return type_t::OBJECT_END;
case '[': return type_t::ARRAY_BEGIN;
case ']': return type_t::ARRAY_END;
case '"': return type_t::STRING;
case 'n': return type_t::NONE;
case 't':
case 'f':
return type_t::BOOLEAN;
// TODO: leading plus isn't valid json, but other similar formats support
// this syntax and it's easier to claim it as a number globally here until
// we do a little refactoring.
case '-':
case '+':
case '0'...'9':
return type_t::NUMBER;
}
unhandled (c);
}
///////////////////////////////////////////////////////////////////////////////
#include "./personality/rfc7519.hpp"
#include "./personality/jsonish.hpp"
template <typename PersonalityT>
const char*
util::json2::event::parse (const std::function<util::json2::callback_t> &cb,
const char *first,
const char *last)
{
auto cursor = first;
PersonalityT p {};
cursor = p.consume_whitespace (cursor, last);
cursor = p.parse_value (cb, cursor, last);
cursor = p.consume_whitespace (cursor, last);
return cursor;
}
//-----------------------------------------------------------------------------
template
const char* util::json2::event::parse<util::json2::personality::rfc7159> (
const std::function<util::json2::callback_t> &,
const char*,
const char*
);
//-----------------------------------------------------------------------------
template
const char* util::json2::event::parse<util::json2::personality::jsonish> (
const std::function<util::json2::callback_t> &,
const char*,
const char*
);

55
json2/event.hpp Normal file
View File

@ -0,0 +1,55 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_JSON2_EVENT_HPP
#define CRUFT_JSON2_EVENT_HPP
#include "./fwd.hpp"
#include <functional>
namespace util::json2::event {
// It is important that scalars come after compound types because it
// simplifies categorisation as we can use a simple '>' to classify the
// types.
//
// the value of the enumerants isn't important, but they might make it
// fractionally easier to visualise in a debugger on some occasions.
enum class type_t {
OBJECT_BEGIN = '{',
OBJECT_END = '}',
ARRAY_BEGIN = '[',
ARRAY_END = ']',
STRING = '"',
NUMBER = '1',
BOOLEAN = 't',
NONE = 'n',
};
struct packet {
type_t type (void) const noexcept;
const char *first;
const char *last;
};
template <typename PersonalityT = personality::rfc7159>
const char*
parse (const std::function<callback_t>&, const char *first, const char *last);
};
#endif

View File

@ -11,35 +11,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#if defined(__UTIL_GEOM_SAMPLE_IPP)
#error
#endif
#ifndef CRUFT_UTIL_JSON2_EXCEPT_HPP
#define CRUFT_UTIL_JSON2_EXCEPT_HPP
#define __UTIL_GEOM_SAMPLE_IPP
#include <exception>
#include "ops.hpp"
namespace util::geom {
// use rejection sampling by default
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename G
>
point<S,T>
sampler<S,T,K,G>::fn (K<S,T> k, G &g)
{
auto b = bounds (k);
namespace util::json2 {
struct error : public std::exception {};
while (true) {
auto p = sample (b, g);
if (intersects (k, p))
return p;
}
}
struct parse_error : public error {
parse_error (const char *_position):
position (_position)
{ ; }
const char *position;
};
struct overrun_error : public parse_error {
using parse_error::parse_error;
};
}
#endif

47
json2/fwd.hpp Normal file
View File

@ -0,0 +1,47 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_JSON2_FWD_HPP
#define CRUFT_UTIL_JSON2_FWD_HPP
#include "../preprocessor.hpp"
namespace util::json2 {
namespace personality {
template <typename> struct base;
struct rfc7159;
struct jsonish;
#define MAP_JSON2_PERSONALITY_TYPES(FUNC) \
MAP0(FUNC, \
util::json2::personality::rfc7159,\
util::json2::personality::jsonish)
}
namespace event {
enum class type_t;
struct packet;
}
using callback_t = void(const event::packet&);
struct error;
struct parse_error;
struct overrun_error;
}
#endif

332
json2/personality/base.cpp Normal file
View File

@ -0,0 +1,332 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#include "./base.hpp"
#include "../event.hpp"
#include "../except.hpp"
#include "../../debug.hpp"
#include "./rfc7519.hpp"
#include "./jsonish.hpp"
using util::json2::personality::base;
///////////////////////////////////////////////////////////////////////////////
static const char*
expect [[nodiscard]] (const char *first, const char *last, const char value)
{
if (first == last || *first != value)
throw util::json2::parse_error {first};
return first + 1;
}
///////////////////////////////////////////////////////////////////////////////
template <typename ParentT>
const char*
base<ParentT>::consume_whitespace (const char *first, const char *last) noexcept
{
auto cursor = first;
while (cursor != last) {
switch (*cursor) {
case 0x20:
case 0x09:
case 0x0A:
case 0x0D:
++cursor;
continue;
}
break;
}
return cursor;
}
///////////////////////////////////////////////////////////////////////////////
template <typename ParentT>
const char*
base<ParentT>::parse_number (const std::function<util::json2::callback_t> &cb,
const char *first,
const char *last)
{
(void)last;
// number: minus? int frac? exp?
auto cursor = first;
// minus: '-'
if (*cursor == '-')
++cursor;
// int: '0' | [1-9] DIGIT*
switch (*cursor) {
case '1'...'9':
{
++cursor;
while ('0' <= *cursor && *cursor <= '9')
++cursor;
break;
}
case '0':
// leading zero means we _must_ be parsing a fractional value so we
// look ahead to ensure we're about to do so. note that we don't use
// `expect' here because it implies consumption of '.'
++cursor;
if (*cursor != '.')
throw util::json2::parse_error { cursor };
break;
default:
throw util::json2::parse_error { cursor };
}
// frac: '.' digit+
if (*cursor == '.') {
++cursor;
auto frac_start = cursor;
while ('0' <= *cursor && *cursor <= '9')
++cursor;
if (frac_start == cursor)
throw util::json2::parse_error { cursor };
}
// exp: [eE] [-+]? digit+
if (*cursor == 'e' || *cursor == 'E') {
++cursor;
if (*cursor == '-' || *cursor == '+')
++cursor;
auto exp_digits = cursor;
while ('0' <= *cursor && *cursor <= '9')
++cursor;
if (exp_digits == cursor)
throw util::json2::parse_error { cursor };
}
cb ({ first, cursor });
return cursor;
}
//-----------------------------------------------------------------------------
template <typename ParentT>
template <int N>
const char*
base<ParentT>::parse_literal (const std::function<util::json2::callback_t> &cb,
const char *first,
const char *last,
const char (&value)[N])
{
CHECK_LE (first, last);
if (last - first < N - 1)
throw util::json2::overrun_error { first };
if (!std::equal (first, first + N - 1, value))
throw util::json2::parse_error { first };
cb ({ first, first + N - 1 });
return first + N - 1;
}
//-----------------------------------------------------------------------------
template <typename ParentT>
const char*
base<ParentT>::parse_string (const std::function<util::json2::callback_t> &cb,
const char *first,
const char *last)
{
CHECK_LE (first, last);
auto cursor = first;
cursor = expect (cursor, last, '"');
for ( ; cursor != last && *cursor != '"'; ) {
// advance the simple case first; unescaped character
if (*cursor++ != '\\') {
continue;
}
if (*cursor++ == 'u') {
for (int i = 0; i < 4; ++i) {
switch (*cursor) {
case 'a'...'f':
case 'A'...'F':
++cursor;
continue;
default:
throw util::json2::parse_error { cursor };
}
}
}
}
cursor = expect (cursor, last, '"');
cb ({ first, cursor });
return cursor;
}
//-----------------------------------------------------------------------------
template <typename ParentT>
const char*
base<ParentT>::parse_array (const std::function<util::json2::callback_t> &cb,
const char *first,
const char *last)
{
CHECK_LE (first, last);
auto cursor = first;
if (*cursor != '[')
throw util::json2::parse_error {cursor};
cb ({ cursor, cursor + 1 });
++cursor;
cursor = ParentT::consume_whitespace (cursor, last);
if (*cursor == ']') {
cb ({cursor, cursor + 1});
return ++cursor;
}
cursor = ParentT::parse_value (cb, cursor, last);
if (*cursor == ']') {
cb ({cursor, cursor + 1});
return ++cursor;
}
do {
cursor = ParentT::consume_whitespace (cursor, last);
cursor = expect (cursor, last, ',');
cursor = ParentT::consume_whitespace (cursor, last);
cursor = ParentT::parse_value (cb, cursor, last);
} while (*cursor != ']');
cb ({cursor, cursor + 1});
++cursor;
return cursor;
}
//-----------------------------------------------------------------------------
template <typename ParentT>
const char*
base<ParentT>::parse_object (const std::function<util::json2::callback_t> &cb,
const char *first,
const char *last)
{
CHECK_LE (first, last);
auto cursor = first;
cursor = expect (cursor, last, '{');
cb ({ cursor - 1, cursor });
cursor = ParentT::consume_whitespace (cursor, last);
if (*cursor == '}') {
cb ({cursor, cursor + 1});
return ++cursor;
};
auto parse_member = [] (auto _cb, auto _cursor, auto _last) {
_cursor = ParentT::parse_key (_cb, _cursor, _last);
_cursor = ParentT::consume_whitespace (_cursor, _last);
_cursor = expect (_cursor, _last, ':');
_cursor = ParentT::consume_whitespace (_cursor, _last);
_cursor = ParentT::parse_value (_cb, _cursor, _last);
_cursor = ParentT::consume_whitespace (_cursor, _last);
return _cursor;
};
cursor = parse_member (cb, cursor, last);
if (*cursor == '}') {
cb ({cursor, cursor + 1});
return ++cursor;
}
do {
cursor = expect (cursor, last, ',');
cursor = ParentT::consume_whitespace (cursor, last);
cursor = parse_member (cb, cursor, last);
} while (*cursor != '}');
cursor = expect (cursor, last, '}');
cb ({cursor - 1, cursor});
return cursor;
}
///////////////////////////////////////////////////////////////////////////////
template <typename ParentT>
const char*
base<ParentT>::parse_value (const std::function<util::json2::callback_t> &cb,
const char *first,
const char *last)
{
switch (*first) {
case '+':
case '-':
case '0'...'9':
return ParentT::parse_number (cb, first, last);
case '"':
return ParentT::parse_string (cb, first, last);
case 't': return ParentT::parse_literal (cb, first, last, "true");
case 'f': return ParentT::parse_literal (cb, first, last, "false");
case 'n': return ParentT::parse_literal (cb, first, last, "null");
case '[': return ParentT::parse_array (cb, first, last);
case '{': return ParentT::parse_object (cb, first, last);
}
return ParentT::parse_unknown (cb, first, last);
}
///////////////////////////////////////////////////////////////////////////////
template <typename ParentT>
const char*
base<ParentT>::parse_unknown (const std::function<util::json2::callback_t>&,
const char *first,
const char *last)
{
(void)last;
throw parse_error {first};
};
//-----------------------------------------------------------------------------
#define INSTANTIATE(KLASS) template struct util::json2::personality::base<KLASS>;
MAP_JSON2_PERSONALITY_TYPES (INSTANTIATE)

View File

@ -0,0 +1,90 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_JSON2_PERSONALITY_BASE_HPP
#define CRUFT_UTIL_JSON2_PERSONALITY_BASE_HPP
#include "../fwd.hpp"
#include <functional>
namespace util::json2::personality {
template <typename T>
struct base {
static const char*
consume_whitespace [[nodiscard]] (const char *first, const char *last) noexcept;
static const char*
parse_number [[nodiscard]] (
const std::function<callback_t>&,
const char *first,
const char *last
);
template <int N>
static const char*
parse_literal [[nodiscard]] (
const std::function<callback_t>&,
const char *first,
const char *last,
const char (&value)[N]
);
static const char*
parse_string [[nodiscard]] (
const std::function<callback_t>&,
const char *first,
const char *last
);
static const char*
parse_array [[nodiscard]] (
const std::function<callback_t>&,
const char *first,
const char *last
);
static const char*
parse_object [[nodiscard]] (
const std::function<callback_t>&,
const char *first,
const char *last
);
static const char*
parse_value [[nodiscard]] (
const std::function<callback_t>&,
const char *first,
const char *last
);
static const char*
parse_unknown [[noreturn]] (
const std::function<callback_t>&,
const char *first,
const char *last
);
};
};
#endif

View File

@ -0,0 +1,201 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#include "./jsonish.hpp"
#include "./base.hpp"
#include "../event.hpp"
#include "../except.hpp"
#include "../../debug.hpp"
using util::json2::personality::jsonish;
///////////////////////////////////////////////////////////////////////////////
const char*
jsonish::consume_whitespace (const char *first, const char *last) noexcept
{
auto cursor = base<jsonish>::consume_whitespace (first, last);
// consume a comment
if (cursor != last && *cursor == '#') {
while (cursor != last && *cursor != '\n')
++cursor;
return consume_whitespace (cursor, last);
}
return cursor;
}
///////////////////////////////////////////////////////////////////////////////
// format is:
// int: '0x' hex+ | '0' oct+ | '0b' bit+
//
// float: significand exp?
// significand: digit+ ('.' digit*)?
// exp: [eE] sign? digit+
//
// number: [+-] (int | float)
const char*
jsonish::parse_number (const std::function<callback_t> &cb,
const char *first,
const char *last)
{
auto cursor = first;
if (cursor != last && (*cursor == '+' || *cursor == '-'))
++cursor;
if (cursor != last && *cursor == '0') {
++cursor;
if (cursor == last)
throw parse_error {cursor};
char max = '9';
switch (*cursor) {
case 'x': {
// parse the hex integer here because we can simplify the
// remaining cases somewhat if we don't need to care about the
// multiple ranges of valid digits.
++cursor;
auto digit_start = cursor;
while (cursor != last && ('0' <= *cursor && *cursor <= '9' ||
'a' <= *cursor && *cursor <= 'f' ||
'A' <= *cursor && *cursor <= 'F'))
++cursor;
if (digit_start == cursor)
throw parse_error {cursor};
cb ({first, cursor});
return cursor;
};
case 'b': max = '1'; break;
case '0'...'7': max = '7'; break;
case '.':
goto frac;
}
auto digit_start = ++cursor;
while (cursor != last && '0' <= *cursor && *cursor <= max)
++cursor;
if (digit_start == cursor)
throw parse_error {cursor};
cb ({first, cursor});
return cursor;
}
while (cursor != last && '0' <= *cursor && *cursor <= '9')
++cursor;
if (cursor == last)
goto done;
if (*cursor != '.')
goto exp;
frac:
++cursor;
while (cursor != last && *cursor >= '0' && *cursor <= '9')
++cursor;
if (cursor == last)
goto done;
exp:
if (cursor != last && (*cursor == 'e' || *cursor == 'E')) {
++cursor;
if (cursor != last && (*cursor == '+' || *cursor == '-'))
++cursor;
auto digit_start = cursor;
while (cursor != last && '0' <= *cursor && *cursor <= '9')
++cursor;
if (digit_start == cursor)
throw parse_error {cursor};
}
if (first == cursor)
throw parse_error {cursor};
done:
cb ({first, cursor});
return cursor;
}
///////////////////////////////////////////////////////////////////////////////
const char*
jsonish::parse_key (const std::function<callback_t> &cb,
const char *first,
const char *last)
{
auto cursor = first;
if (cursor == last)
throw parse_error {cursor};
// must start with alpha or underscore
switch (*cursor) {
case 'a'...'z':
case 'A'...'Z':
case '_':
++cursor;
break;
default:
throw parse_error {cursor};
}
while (cursor != last) {
switch (*cursor) {
case 'a'...'z':
case 'A'...'Z':
case '_':
case '0'...'9':
++cursor;
break;
default:
cb ({first, cursor});
return cursor;
}
}
cb ({first, cursor});
return cursor;
}
///////////////////////////////////////////////////////////////////////////////
const char*
jsonish::parse_string (const std::function<callback_t> &cb,
const char *first,
const char *last)
{
if (first == last)
throw parse_error {first};
if (*first == '"')
return base<jsonish>::parse_string (cb, first, last);
else
return parse_key (cb, first, last);
}

View File

@ -0,0 +1,101 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_JSON2_PERSONALITY_JSONISH_HPP
#define CRUFT_UTIL_JSON2_PERSONALITY_JSONISH_HPP
#include "../fwd.hpp"
#include "./base.hpp"
#include <functional>
namespace util::json2::personality {
struct jsonish {
static const char*
consume_whitespace [[nodiscard]] (
const char *first,
const char *last
) noexcept;
static const char*
parse_value [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first, const char *last
) { return base<jsonish>::parse_value (cb, first, last); }
static const char*
parse_number [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first,
const char *last
);
template <int N>
static const char*
parse_literal [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first,
const char *last,
const char (&value)[N]
) { return base<jsonish>::parse_literal (cb, first, last, value); }
static const char*
parse_string [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first,
const char *last
);
static const char*
parse_array [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first,
const char *last
) { return base<jsonish>::parse_array (cb, first, last); }
static const char*
parse_key [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first,
const char *last);
static const char*
parse_object [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first,
const char *last
) { return base<jsonish>::parse_object (cb, first, last); }
static const char*
parse_unknown [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first,
const char *last
) { return parse_string (cb, first, last); }
};
};
#endif

View File

@ -0,0 +1,21 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#include "./rfc7519.hpp"
#include "./base.hpp"
using util::json2::personality::rfc7159;

View File

@ -0,0 +1,100 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_JSON2_PERSONALITY_RFC7159_HPP
#define CRUFT_UTIL_JSON2_PERSONALITY_RFC7159_HPP
#include "./base.hpp"
#include "../fwd.hpp"
#include <functional>
namespace util::json2::personality {
struct rfc7159 {
static const char*
consume_whitespace [[nodiscard]] (const char *first, const char *last) noexcept
{ return base<rfc7159>::consume_whitespace (first, last); }
static const char*
parse_value [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first, const char *last
) { return base<rfc7159>::parse_value (cb, first, last); }
static const char*
parse_number [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first,
const char *last
) { return base<rfc7159>::parse_number (cb, first, last); }
template <int N>
static const char*
parse_literal [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first,
const char *last,
const char (&value)[N]
) { return base<rfc7159>::parse_literal (cb, first, last, value); }
static const char*
parse_string [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first,
const char *last
) { return base<rfc7159>::parse_string (cb, first, last); }
static const char*
parse_array [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first,
const char *last
) { return base<rfc7159>::parse_array (cb, first, last); }
static const char*
parse_key [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first,
const char *last)
{ return parse_string (cb, first, last); }
static const char*
parse_object [[nodiscard]] (
const std::function<callback_t> &cb,
const char *first,
const char *last
) { return base<rfc7159>::parse_object (cb, first, last); }
static const char *
parse_unknown [[noreturn]] (
const std::function<callback_t> &cb,
const char *first,
const char *last)
{ throw base<rfc7159>::parse_unknown (cb, first, last); }
};
};
#endif

1
json2/tree.cpp Normal file
View File

@ -0,0 +1 @@
#include "./tree.hpp"

View File

@ -11,13 +11,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_ALLOC_STACK_IPP
#error
#endif
#define __UTIL_ALLOC_STACK_IPP
#ifndef CRUFT_JSON2_TREE_HPP
#define CRUFT_JSON2_TREE_HPP
#endif

View File

@ -45,7 +45,7 @@ namespace util {
DEBUG /** debug-level messages */
};
#define MAP_LEVEL_T(F) MAP(F, EMERGENCY, ALERT, CRITICAL, ERROR, WARN, NOTICE, INFO, DEBUG)
#define MAP_LEVEL_T(F) MAP0(F, EMERGENCY, ALERT, CRITICAL, ERROR, WARN, NOTICE, INFO, DEBUG)
constexpr auto DEFAULT_LOG_LEVEL = NOTICE;

View File

@ -253,23 +253,25 @@ namespace util {
///////////////////////////////////////////////////////////////////////////////
// Rounding
/// round T up to the nearest multiple of U
template <typename T, typename U>
inline
typename std::common_type<
std::enable_if_t<std::is_integral<T>::value,T>,
std::enable_if_t<std::is_integral<U>::value,U>
>::type
round_to (T value, U size)
round_up (T value, U size)
{
if (value % size == 0)
return value;
return value + (size - value % size);
// we perform this as two steps to avoid unnecessarily incrementing when
// remainder is zero.
if (value % size)
value += size - value % size;
return value;
}
//-----------------------------------------------------------------------------
///----------------------------------------------------------------------------
/// round T up to the nearest power-of-2
template <typename T>
constexpr
std::enable_if_t<
@ -290,7 +292,8 @@ namespace util {
}
//-----------------------------------------------------------------------------
///----------------------------------------------------------------------------
/// round T up to the nearest multiple of U and return the quotient.
template <typename T, typename U>
constexpr std::enable_if_t<
std::is_integral<T>::value &&
@ -344,15 +347,17 @@ namespace util {
template <typename ValueT, typename BaseT>
constexpr
std::enable_if_t<
std::is_integral<ValueT>::value && std::is_unsigned<BaseT>::value,
unsigned
std::is_integral_v<ValueT> && std::is_integral_v<BaseT>,
int
>
digits (ValueT value, BaseT base) noexcept
{
assert (base > 0);
if (value < 0)
value *= -1;
unsigned tally = 1;
int tally = 1;
while (value /= base)
++tally;
@ -582,7 +587,16 @@ namespace util {
///////////////////////////////////////////////////////////////////////////
/// Variadic minimum
template <typename T>
// disable the single parameter version for non-arithmetic types so that
// min for coord types is unambiguous. allow pointers too because it
// doesn't add ambiguity and it simplifies some memory juggling.
template <
typename T,
typename = std::enable_if_t<
std::is_arithmetic_v<T> || std::is_pointer_v<T>, void
>
>
constexpr T
min (const T a)
{ return a; }
@ -604,7 +618,7 @@ namespace util {
//-------------------------------------------------------------------------
/// Variadic maximum
template <typename T>
constexpr std::enable_if_t<std::is_arithmetic_v<T>, T>
constexpr std::enable_if_t<std::is_arithmetic_v<T> || std::is_pointer_v<T>, T>
max (const T a)
{ return a; }
@ -628,7 +642,10 @@ namespace util {
// min/max clamping
template <typename T, typename U, typename V>
constexpr
T
std::enable_if_t<
std::is_scalar_v<T> && std::is_scalar_v<U> && std::is_scalar_v<V>,
std::common_type_t<T,U,V>
>
limit (const T val, const U lo, const V hi)
{
assert (lo <= hi);
@ -756,32 +773,48 @@ namespace util {
//-------------------------------------------------------------------------
// lo_uint -> hi_uint
template <typename T, typename U>
constexpr
typename std::enable_if<
std::is_unsigned<T>::value &&
std::is_unsigned<U>::value &&
sizeof (T) < sizeof (U), U
>::type
renormalise (T t)
template <
typename SrcT,
typename DstT,
typename = std::enable_if_t<
std::is_unsigned<SrcT>::value &&
std::is_unsigned<DstT>::value &&
sizeof (SrcT) < sizeof (DstT), DstT
>
>
constexpr DstT
renormalise (SrcT src)
{
static_assert (sizeof (T) < sizeof (U),
// we can make some simplifying assumptions for the shift distances if
// we assume the integers are powers of two. this is probably going to
// be the case for every conceivable input type, but we don't want to
// get caught out if we extend this routine to more general types
// (eg, OpenGL DEPTH24).
static_assert (is_pow2 (sizeof (SrcT)));
static_assert (is_pow2 (sizeof (DstT)));
static_assert (sizeof (SrcT) < sizeof (DstT),
"assumes bit creation is required to fill space");
// we need to create bits. fill the output integer with copies of ourself.
// this is approximately correct in the general case (introducing a small
// linear positive bias), but allows us to fill the output space in the
// case of input maximum.
static_assert (sizeof (U) % sizeof (T) == 0,
// linear positive bias), but it allows us to set all output bits high
// when we receive the maximum allowable input value.
static_assert (sizeof (DstT) % sizeof (SrcT) == 0,
"assumes integer multiple of sizes");
U out = 0;
for (size_t i = 0; i < sizeof (U) / sizeof (T); ++i)
out |= U (t) << sizeof (T) * 8 * i;
return out;
// clang#xxxx: ideally we wouldn't use a multiplication here, but we
// trigger a segfault in clang-5.0 when using ld.gold+lto;
// 'X86 DAG->DAG Instruction Selection'
//
// create a mask of locations we'd like copies of the src bit pattern.
//
// this replicates repeatedly or'ing and shifting dst with itself.
DstT dst { 1 };
for (unsigned i = sizeof (SrcT) * 8; i < sizeof (DstT) * 8; i *= 2)
dst |= dst << i;
return dst * src;
}

View File

@ -27,14 +27,6 @@ using util::matrix;
///////////////////////////////////////////////////////////////////////////////
template <std::size_t Rows, std::size_t Cols, typename T>
matrix<Rows,Cols,T>&
matrix<Rows,Cols,T>::invert (void)
{
return *this = inverse ();
}
//-----------------------------------------------------------------------------
//template <std::size_t S, typename T>
//matrix<S,T>&

View File

@ -51,28 +51,81 @@ namespace util {
T values[rows][cols];
///////////////////////////////////////////////////////////////////////
// index operators return a pointer into the data array so that
// multidimensional array syntax can be used transparently on this
// type.
constexpr auto& operator[] (std::size_t idx) { return values[idx]; }
constexpr const auto& operator[] (std::size_t idx) const { return values[idx]; }
T* data (void);
const T* data (void) const;
//---------------------------------------------------------------------
constexpr auto
data (void) noexcept
{
return begin ();
}
const T* begin (void) const;
const T* end (void) const;
T* begin (void);
T* end (void);
const T* cbegin (void) const;
const T* cend (void) const;
//---------------------------------------------------------------------
constexpr auto
data (void) const noexcept
{
return begin ();
}
//---------------------------------------------------------------------
constexpr auto
begin (void) const noexcept
{
return &(*this)[0][0];
}
//---------------------------------------------------------------------
constexpr auto
end (void) const noexcept
{
return &(*this)[Rows][0];
}
//---------------------------------------------------------------------
constexpr auto
begin (void) noexcept
{
return &(*this)[0][0];
}
//---------------------------------------------------------------------
constexpr auto
end (void) noexcept
{
return &(*this)[Rows][0];
}
//---------------------------------------------------------------------
constexpr auto
cbegin (void) const noexcept
{
return begin ();
}
//---------------------------------------------------------------------
constexpr auto
cend (void) const noexcept
{
return end ();
}
///////////////////////////////////////////////////////////////////////
T determinant (void) const;
matrix inverse (void) const;
matrix& invert (void);
matrix inverse_affine (void) const;
matrix& invert_affine (void);
matrix inverse (void) const;
matrix
inverse_affine (void) const
{
// TODO: ensure we have specialisations for typical dimensions
return inverse ();
}
template <typename VectorT>
@ -91,7 +144,12 @@ namespace util {
template <typename U>
matrix<Rows,Cols,U>
cast (void) const;
cast (void) const noexcept
{
util::matrix<Rows,Cols,T> out;
std::copy (cbegin (), cend (), std::begin (out));
return out;
}
// Constant matrices
static constexpr matrix identity ();
@ -206,8 +264,12 @@ namespace util {
{
matrix<R1,C2,T> res {};
// we use a column first iteration approach because otherwise we risk
// triggering clang#????
// TODO: iterating over r,c rather than c,r will cause an ICE with
// clang#xxxx: 'X86 DAG->DAG Instruction Selection'.
//
// this is likely related to gold and LTO support. for the time being
// we switch the orders because it appears to confuse the optimiser
// sufficiently. :(
for (std::size_t c = 0; c < C2; ++c) {
for (std::size_t r = 0; r < R1; ++r) {
T accum {0};

View File

@ -41,90 +41,6 @@
//}
//-----------------------------------------------------------------------------
template <std::size_t Rows, std::size_t Cols, typename T>
T*
util::matrix<Rows,Cols,T>::data (void)
{
return begin ();
}
//-----------------------------------------------------------------------------
template <std::size_t Rows, std::size_t Cols, typename T>
const T*
util::matrix<Rows,Cols,T>::data (void) const
{
return begin ();
}
//-----------------------------------------------------------------------------
template <std::size_t Rows, std::size_t Cols, typename T>
const T*
util::matrix<Rows,Cols,T>::begin (void) const
{
return &(*this)[0][0];
}
//-----------------------------------------------------------------------------
template <std::size_t Rows, std::size_t Cols, typename T>
const T*
util::matrix<Rows,Cols,T>::end (void) const
{
return &(*this)[Rows][0];
}
//-----------------------------------------------------------------------------
template <std::size_t Rows, std::size_t Cols, typename T>
const T*
util::matrix<Rows,Cols,T>::cbegin (void) const
{
return begin ();
}
//-----------------------------------------------------------------------------
template <std::size_t Rows, std::size_t Cols, typename T>
const T*
util::matrix<Rows,Cols,T>::cend (void) const
{
return end ();
}
//-----------------------------------------------------------------------------
template <std::size_t Rows, std::size_t Cols, typename T>
T*
util::matrix<Rows,Cols,T>::begin (void)
{
return &(*this)[0][0];
}
//-----------------------------------------------------------------------------
template <std::size_t Rows, std::size_t Cols, typename T>
T*
util::matrix<Rows,Cols,T>::end (void)
{
return &(*this)[Rows][0];
}
///////////////////////////////////////////////////////////////////////////////
template <std::size_t Rows, std::size_t Cols, typename T>
template <typename U>
util::matrix<Rows,Cols,U>
util::matrix<Rows,Cols,T>::cast (void) const
{
util::matrix<Rows,Cols,T> out;
std::copy (cbegin (), cend (), std::begin (out));
return out;
}
///////////////////////////////////////////////////////////////////////////////
#define MATRIX_ELEMENT_OP(OP) \
template <std::size_t Rows, std::size_t Cols, typename T> \

View File

@ -48,7 +48,7 @@ tmpname (std::string &str, size_t length)
str.resize (length);
std::generate_n (str.begin (), length, [&] (void) {
return util::rand::choose (alphanum);
return util::random::choose (alphanum);
});
}
@ -57,7 +57,7 @@ tmpname (std::string &str, size_t length)
circular::circular (size_t bytes)
{
bytes = max (bytes, sizeof (value_type));
bytes = round_to (bytes, pagesize ());
bytes = round_up (bytes, pagesize ());
int fd = -1;

View File

@ -29,7 +29,7 @@ using util::memory::buffer::paged;
///////////////////////////////////////////////////////////////////////////////
paged::paged (size_t bytes, size_t _window):
m_window (round_to (_window, pagesize ()))
m_window (round_up (_window, pagesize ()))
{
// reserve the address region with no access permissions
m_begin = reinterpret_cast<char*> (
@ -40,7 +40,7 @@ paged::paged (size_t bytes, size_t _window):
errno_error::throw_code ();
// remap the initial window with read/write permissions
m_cursor = m_begin + round_to (min (m_window, bytes), pagesize ());
m_cursor = m_begin + round_up (min (m_window, bytes), pagesize ());
if (MAP_FAILED == mmap (m_begin,
m_cursor - m_begin,
PROT_READ | PROT_WRITE,
@ -48,7 +48,7 @@ paged::paged (size_t bytes, size_t _window):
errno_error::throw_code ();
// record the nominal end address
m_end = m_begin + round_to (bytes, pagesize ());
m_end = m_begin + round_up (bytes, pagesize ());
}

View File

@ -42,20 +42,24 @@ namespace util::memory {
// XXX: Generates a "sorry, unimplemented" under GCC (which is
// effectively an ICE). Their bug tracker seems to indicate they don't
// give a fuck, so we can't use this except under clang.
template <typename T, typename U, void (U::*F)(T*)>
template <
typename ValueT,
typename OwnerT,
void (OwnerT::*Func)(ValueT*)
>
class owner_deleter {
public:
owner_deleter (U &owner):
owner_deleter (OwnerT &owner):
m_owner (owner)
{ ; }
inline void operator() (T *t)
inline void operator() (ValueT *t)
{
(m_owner.*F) (t);
(m_owner.*Func) (t);
}
private:
U& m_owner;
OwnerT& m_owner;
};
}

86
parse.cpp Normal file
View File

@ -0,0 +1,86 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#include "./parse.hpp"
#include <cstdlib>
#include <stdexcept>
using util::parse;
///////////////////////////////////////////////////////////////////////////////
template <typename T> struct c_traits;
template <> struct c_traits<long> { static constexpr auto func = strtol; };
template <> struct c_traits<long long> { static constexpr auto func = strtoll; };
template <> struct c_traits<unsigned long> { static constexpr auto func = strtoul; };
template <> struct c_traits<unsigned long long> { static constexpr auto func = strtoull; };
template <> struct c_traits<float> { static constexpr auto func = strtof; };
template <> struct c_traits<double> { static constexpr auto func = strtod; };
template <> struct c_traits<long double> { static constexpr auto func = strtold; };
//-----------------------------------------------------------------------------
template <typename T>
T
c_iparse (const char *first, const char *last)
{
auto tail = const_cast<char *> (last);
auto val = c_traits<T>::func (first, &tail, 0);
if (tail != last)
throw std::invalid_argument ("unable to parse");
return val;
}
//-----------------------------------------------------------------------------
template <typename T>
T
c_fparse (const char *first, const char *last)
{
auto tail = const_cast<char *> (last);
auto val = c_traits<T>::func (first, &tail);
if (tail != last)
throw std::invalid_argument ("unable to parse");
return val;
}
///////////////////////////////////////////////////////////////////////////////
#define C_PARSE(T, KLASS) \
template <> \
T \
util::parse<T> (const char *first, const char *last) \
{ \
return c_ ## KLASS ## parse<T> (first, last); \
}
//-----------------------------------------------------------------------------
C_PARSE(long, i)
C_PARSE(long long, i)
C_PARSE(unsigned long, i)
C_PARSE(unsigned long long, i)
C_PARSE(float, f)
C_PARSE(double, f)
C_PARSE(long double, f)

53
parse.hpp Normal file
View File

@ -0,0 +1,53 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_PARSE_HPP
#define CRUFT_UTIL_PARSE_HPP
#include <cstring>
#include <string>
#include <iterator>
namespace util {
///////////////////////////////////////////////////////////////////////////
/// extracts an instance of a native type T from the string [first, last).
///
/// throws std::invalid_argument when the type cannot be parsed.
template <typename T>
T
parse (const char *first, const char *last);
//-------------------------------------------------------------------------
template <typename T>
T
parse (const char *str)
{
return parse<T> (str, str + strlen (str));
}
//-------------------------------------------------------------------------
template <typename T>
T
parse (const std::string &str)
{
return parse<T> (std::cbegin (str), std::cend (str));
}
}
#endif

View File

@ -37,8 +37,27 @@ namespace util {
template <size_t D> point<D,T> homog (void) const;
static constexpr point<S,T> origin (void);
///////////////////////////////////////////////////////////////////////
static constexpr
auto min (void)
{
return point { std::numeric_limits<T>::lowest () };
}
//-------------------------------------------------------------------
static constexpr
auto max (void)
{
return point { std::numeric_limits<T>::max () };
}
//-------------------------------------------------------------------
static constexpr
point<S,T> origin (void);
///////////////////////////////////////////////////////////////////////
void sanity (void) const;
};

View File

@ -11,11 +11,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
* Copyright 2011-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __POINTER_HPP
#define __POINTER_HPP
#ifndef CRUFT_UTIL_POINTER_HPP
#define CRUFT_UTIL_POINTER_HPP
#include <cstddef>
#include <cstdint>
@ -23,10 +23,13 @@
namespace util {
///////////////////////////////////////////////////////////////////////////
/// round the pointer upwards to satisfy the provided alignment
template <typename T>
T*
constexpr T*
align (T *_ptr, size_t alignment)
{
// we perform this as two steps to avoid unnecessarily incrementing when
// remainder is zero.
auto ptr = reinterpret_cast<uintptr_t> (_ptr);
if (ptr % alignment)
ptr += alignment - ptr % alignment;
@ -34,13 +37,36 @@ namespace util {
}
//-------------------------------------------------------------------------
inline uintptr_t
///------------------------------------------------------------------------
/// round the pointer upwards to satisfy the provided alignment
constexpr inline uintptr_t
align (uintptr_t ptr, size_t alignment)
{
return reinterpret_cast<uintptr_t> (
align (reinterpret_cast<void*> (ptr), alignment)
);
// we perform this as two steps to avoid unnecessarily incrementing when
// remainder is zero.
if (ptr % alignment)
ptr += alignment - ptr % alignment;
return ptr;
}
///------------------------------------------------------------------------
/// round the pointer upwards to the nearest valid alignment for T
template <typename T>
constexpr auto
align (T *t)
{
return align (t, alignof (T));
}
///------------------------------------------------------------------------
/// round the pointer upwards to the nearest valid alignment for T
template <typename T>
constexpr auto
align (uintptr_t ptr)
{
return align (ptr, alignof (T));
}
}

View File

@ -1,455 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2012-2016 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_PREPROCESSOR_HPP
#define __UTIL_PREPROCESSOR_HPP
#define PASTE_DETAIL(x, y) x##y
#define PASTE(x, y) PASTE_DETAIL(x, y)
#define PASTE_LIST(x,y) PASTE(x,y),
#define NAMESPACE_LIST(x,y) x::y,
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
#define STRINGIZE_LIST(x) STRINGIZE(x),
#define STATIC_ASSERT(MSG) static_assert(false, MSG);
///////////////////////////////////////////////////////////////////////////////
// Varags functional style map
//
// Based off a technique seen on StackOverflow:
// http://stackoverflow.com/questions/11761703/overloading-macro-on-number-of-arguments
#define MAP_0_01(F, X) F(X)
#define MAP_0_02(F, X, ...) F(X)MAP_0_01(F, __VA_ARGS__)
#define MAP_0_03(F, X, ...) F(X)MAP_0_02(F, __VA_ARGS__)
#define MAP_0_04(F, X, ...) F(X)MAP_0_03(F, __VA_ARGS__)
#define MAP_0_05(F, X, ...) F(X)MAP_0_04(F, __VA_ARGS__)
#define MAP_0_06(F, X, ...) F(X)MAP_0_05(F, __VA_ARGS__)
#define MAP_0_07(F, X, ...) F(X)MAP_0_06(F, __VA_ARGS__)
#define MAP_0_08(F, X, ...) F(X)MAP_0_07(F, __VA_ARGS__)
#define MAP_0_09(F, X, ...) F(X)MAP_0_08(F, __VA_ARGS__)
#define MAP_0_10(F, X, ...) F(X)MAP_0_09(F, __VA_ARGS__)
#define MAP_0_11(F, X, ...) F(X)MAP_0_10(F, __VA_ARGS__)
#define MAP_0_12(F, X, ...) F(X)MAP_0_11(F, __VA_ARGS__)
#define MAP_0_13(F, X, ...) F(X)MAP_0_12(F, __VA_ARGS__)
#define MAP_0_14(F, X, ...) F(X)MAP_0_13(F, __VA_ARGS__)
#define MAP_0_15(F, X, ...) F(X)MAP_0_14(F, __VA_ARGS__)
#define MAP_0_16(F, X, ...) F(X)MAP_0_15(F, __VA_ARGS__)
#define MAP_0_17(F, X, ...) F(X)MAP_0_16(F, __VA_ARGS__)
#define MAP_0_18(F, X, ...) F(X)MAP_0_17(F, __VA_ARGS__)
#define MAP_0_19(F, X, ...) F(X)MAP_0_18(F, __VA_ARGS__)
#define MAP_0_20(F, X, ...) F(X)MAP_0_19(F, __VA_ARGS__)
#define MAP_0_21(F, X, ...) F(X)MAP_0_20(F, __VA_ARGS__)
#define MAP_0_22(F, X, ...) F(X)MAP_0_21(F, __VA_ARGS__)
#define MAP_0_23(F, X, ...) F(X)MAP_0_22(F, __VA_ARGS__)
#define MAP_0_24(F, X, ...) F(X)MAP_0_23(F, __VA_ARGS__)
#define MAP_0_25(F, X, ...) F(X)MAP_0_24(F, __VA_ARGS__)
#define MAP_0_26(F, X, ...) F(X)MAP_0_25(F, __VA_ARGS__)
#define MAP_0_27(F, X, ...) F(X)MAP_0_26(F, __VA_ARGS__)
#define MAP_0_28(F, X, ...) F(X)MAP_0_27(F, __VA_ARGS__)
#define MAP_0_29(F, X, ...) F(X)MAP_0_28(F, __VA_ARGS__)
#define MAP_0_30(F, X, ...) F(X)MAP_0_29(F, __VA_ARGS__)
#define MAP_0_31(F, X, ...) F(X)MAP_0_30(F, __VA_ARGS__)
#define MAP_0_32(F, X, ...) F(X)MAP_0_31(F, __VA_ARGS__)
#define MAP_0_33(F, X, ...) F(X)MAP_0_32(F, __VA_ARGS__)
#define MAP_0_34(F, X, ...) F(X)MAP_0_33(F, __VA_ARGS__)
#define MAP_0_35(F, X, ...) F(X)MAP_0_34(F, __VA_ARGS__)
#define MAP_0_36(F, X, ...) F(X)MAP_0_35(F, __VA_ARGS__)
#define MAP_0_37(F, X, ...) F(X)MAP_0_36(F, __VA_ARGS__)
#define MAP_0_38(F, X, ...) F(X)MAP_0_37(F, __VA_ARGS__)
#define MAP_0_39(F, X, ...) F(X)MAP_0_38(F, __VA_ARGS__)
#define MAP_0_40(F, X, ...) F(X)MAP_0_39(F, __VA_ARGS__)
#define MAP_0_41(F, X, ...) F(X)MAP_0_40(F, __VA_ARGS__)
#define MAP_0_42(F, X, ...) F(X)MAP_0_41(F, __VA_ARGS__)
#define MAP_0_43(F, X, ...) F(X)MAP_0_42(F, __VA_ARGS__)
#define MAP_0_44(F, X, ...) F(X)MAP_0_43(F, __VA_ARGS__)
#define MAP_0_45(F, X, ...) F(X)MAP_0_44(F, __VA_ARGS__)
#define MAP_0_46(F, X, ...) F(X)MAP_0_45(F, __VA_ARGS__)
#define MAP_0_47(F, X, ...) F(X)MAP_0_46(F, __VA_ARGS__)
#define MAP_0_48(F, X, ...) F(X)MAP_0_47(F, __VA_ARGS__)
#define MAP_0_49(F, X, ...) F(X)MAP_0_48(F, __VA_ARGS__)
#define MAP_0_50(F, X, ...) F(X)MAP_0_49(F, __VA_ARGS__)
#define MAP_0_51(F, X, ...) F(X)MAP_0_50(F, __VA_ARGS__)
#define MAP_0_52(F, X, ...) F(X)MAP_0_51(F, __VA_ARGS__)
#define MAP_0_53(F, X, ...) F(X)MAP_0_52(F, __VA_ARGS__)
#define MAP_0_54(F, X, ...) F(X)MAP_0_53(F, __VA_ARGS__)
#define MAP_0_55(F, X, ...) F(X)MAP_0_54(F, __VA_ARGS__)
#define MAP_0_56(F, X, ...) F(X)MAP_0_55(F, __VA_ARGS__)
#define MAP_0_57(F, X, ...) F(X)MAP_0_56(F, __VA_ARGS__)
#define MAP_0_58(F, X, ...) F(X)MAP_0_57(F, __VA_ARGS__)
#define MAP_0_59(F, X, ...) F(X)MAP_0_58(F, __VA_ARGS__)
#define MAP_0_60(F, X, ...) F(X)MAP_0_59(F, __VA_ARGS__)
#define MAP_0_61(F, X, ...) F(X)MAP_0_60(F, __VA_ARGS__)
#define MAP_0_62(F, X, ...) F(X)MAP_0_61(F, __VA_ARGS__)
#define MAP_0_63(F, X, ...) F(X)MAP_0_62(F, __VA_ARGS__)
#define MAP_0_64(F, X, ...) F(X)MAP_0_63(F, __VA_ARGS__)
#define MAP_0_65(F, X, ...) F(X)MAP_0_64(F, __VA_ARGS__)
#define MAP_0_66(F, X, ...) F(X)MAP_0_65(F, __VA_ARGS__)
#define MAP_0_67(F, X, ...) F(X)MAP_0_66(F, __VA_ARGS__)
#define MAP_0_68(F, X, ...) F(X)MAP_0_67(F, __VA_ARGS__)
#define MAP_0_69(F, X, ...) F(X)MAP_0_68(F, __VA_ARGS__)
#define MAP_0_70(F, X, ...) F(X)MAP_0_69(F, __VA_ARGS__)
#define MAP_0_71(F, X, ...) F(X)MAP_0_70(F, __VA_ARGS__)
#define MAP_0_72(F, X, ...) F(X)MAP_0_71(F, __VA_ARGS__)
#define MAP_0_73(F, X, ...) F(X)MAP_0_72(F, __VA_ARGS__)
#define MAP_0_74(F, X, ...) F(X)MAP_0_73(F, __VA_ARGS__)
#define MAP_0_75(F, X, ...) F(X)MAP_0_74(F, __VA_ARGS__)
#define MAP_0_76(F, X, ...) F(X)MAP_0_75(F, __VA_ARGS__)
#define MAP_0_77(F, X, ...) F(X)MAP_0_76(F, __VA_ARGS__)
#define MAP_0_78(F, X, ...) F(X)MAP_0_77(F, __VA_ARGS__)
#define MAP_0_79(F, X, ...) F(X)MAP_0_78(F, __VA_ARGS__)
#define MAP_0_80(F, X, ...) F(X)MAP_0_79(F, __VA_ARGS__)
#define MAP_0_81(F, X, ...) F(X)MAP_0_80(F, __VA_ARGS__)
#define MAP_0_82(F, X, ...) F(X)MAP_0_81(F, __VA_ARGS__)
#define MAP_0_83(F, X, ...) F(X)MAP_0_82(F, __VA_ARGS__)
#define MAP_0_84(F, X, ...) F(X)MAP_0_83(F, __VA_ARGS__)
#define MAP_0_85(F, X, ...) F(X)MAP_0_84(F, __VA_ARGS__)
#define MAP_0_86(F, X, ...) F(X)MAP_0_85(F, __VA_ARGS__)
#define MAP_0_87(F, X, ...) F(X)MAP_0_86(F, __VA_ARGS__)
#define MAP_0_88(F, X, ...) F(X)MAP_0_87(F, __VA_ARGS__)
#define MAP_0_89(F, X, ...) F(X)MAP_0_88(F, __VA_ARGS__)
#define MAP_0_90(F, X, ...) F(X)MAP_0_89(F, __VA_ARGS__)
#define MAP_0_91(F, X, ...) F(X)MAP_0_90(F, __VA_ARGS__)
#define MAP_0_92(F, X, ...) F(X)MAP_0_91(F, __VA_ARGS__)
#define MAP_0_93(F, X, ...) F(X)MAP_0_92(F, __VA_ARGS__)
#define MAP_0_94(F, X, ...) F(X)MAP_0_93(F, __VA_ARGS__)
#define MAP_0_95(F, X, ...) F(X)MAP_0_94(F, __VA_ARGS__)
#define MAP_0_96(F, X, ...) F(X)MAP_0_95(F, __VA_ARGS__)
#define MAP_1_01(F, A, X) F(A, X)
#define MAP_1_02(F, A, X, ...) F(A, X)MAP_1_01(F, A, __VA_ARGS__)
#define MAP_1_03(F, A, X, ...) F(A, X)MAP_1_02(F, A, __VA_ARGS__)
#define MAP_1_04(F, A, X, ...) F(A, X)MAP_1_03(F, A, __VA_ARGS__)
#define MAP_1_05(F, A, X, ...) F(A, X)MAP_1_04(F, A, __VA_ARGS__)
#define MAP_1_06(F, A, X, ...) F(A, X)MAP_1_05(F, A, __VA_ARGS__)
#define MAP_1_07(F, A, X, ...) F(A, X)MAP_1_06(F, A, __VA_ARGS__)
#define MAP_1_08(F, A, X, ...) F(A, X)MAP_1_07(F, A, __VA_ARGS__)
#define MAP_1_09(F, A, X, ...) F(A, X)MAP_1_08(F, A, __VA_ARGS__)
#define MAP_1_10(F, A, X, ...) F(A, X)MAP_1_09(F, A, __VA_ARGS__)
#define MAP_1_11(F, A, X, ...) F(A, X)MAP_1_10(F, A, __VA_ARGS__)
#define MAP_1_12(F, A, X, ...) F(A, X)MAP_1_11(F, A, __VA_ARGS__)
#define MAP_1_13(F, A, X, ...) F(A, X)MAP_1_12(F, A, __VA_ARGS__)
#define MAP_1_14(F, A, X, ...) F(A, X)MAP_1_13(F, A, __VA_ARGS__)
#define MAP_1_15(F, A, X, ...) F(A, X)MAP_1_14(F, A, __VA_ARGS__)
#define MAP_1_16(F, A, X, ...) F(A, X)MAP_1_15(F, A, __VA_ARGS__)
#define MAP_1_17(F, A, X, ...) F(A, X)MAP_1_16(F, A, __VA_ARGS__)
#define MAP_1_18(F, A, X, ...) F(A, X)MAP_1_17(F, A, __VA_ARGS__)
#define MAP_1_19(F, A, X, ...) F(A, X)MAP_1_18(F, A, __VA_ARGS__)
#define MAP_1_20(F, A, X, ...) F(A, X)MAP_1_19(F, A, __VA_ARGS__)
#define MAP_1_21(F, A, X, ...) F(A, X)MAP_1_20(F, A, __VA_ARGS__)
#define MAP_1_22(F, A, X, ...) F(A, X)MAP_1_21(F, A, __VA_ARGS__)
#define MAP_1_23(F, A, X, ...) F(A, X)MAP_1_22(F, A, __VA_ARGS__)
#define MAP_1_24(F, A, X, ...) F(A, X)MAP_1_23(F, A, __VA_ARGS__)
#define MAP_1_25(F, A, X, ...) F(A, X)MAP_1_24(F, A, __VA_ARGS__)
#define MAP_1_26(F, A, X, ...) F(A, X)MAP_1_25(F, A, __VA_ARGS__)
#define MAP_1_27(F, A, X, ...) F(A, X)MAP_1_26(F, A, __VA_ARGS__)
#define MAP_1_28(F, A, X, ...) F(A, X)MAP_1_27(F, A, __VA_ARGS__)
#define MAP_1_29(F, A, X, ...) F(A, X)MAP_1_28(F, A, __VA_ARGS__)
#define MAP_1_30(F, A, X, ...) F(A, X)MAP_1_29(F, A, __VA_ARGS__)
#define MAP_1_31(F, A, X, ...) F(A, X)MAP_1_30(F, A, __VA_ARGS__)
#define MAP_1_32(F, A, X, ...) F(A, X)MAP_1_31(F, A, __VA_ARGS__)
#define MAP_1_33(F, A, X, ...) F(A, X)MAP_1_32(F, A, __VA_ARGS__)
#define MAP_1_34(F, A, X, ...) F(A, X)MAP_1_33(F, A, __VA_ARGS__)
#define MAP_1_35(F, A, X, ...) F(A, X)MAP_1_34(F, A, __VA_ARGS__)
#define MAP_1_36(F, A, X, ...) F(A, X)MAP_1_35(F, A, __VA_ARGS__)
#define MAP_1_37(F, A, X, ...) F(A, X)MAP_1_36(F, A, __VA_ARGS__)
#define MAP_1_38(F, A, X, ...) F(A, X)MAP_1_37(F, A, __VA_ARGS__)
#define MAP_1_39(F, A, X, ...) F(A, X)MAP_1_38(F, A, __VA_ARGS__)
#define MAP_1_40(F, A, X, ...) F(A, X)MAP_1_39(F, A, __VA_ARGS__)
#define MAP_1_41(F, A, X, ...) F(A, X)MAP_1_40(F, A, __VA_ARGS__)
#define MAP_1_42(F, A, X, ...) F(A, X)MAP_1_41(F, A, __VA_ARGS__)
#define MAP_1_43(F, A, X, ...) F(A, X)MAP_1_42(F, A, __VA_ARGS__)
#define MAP_1_44(F, A, X, ...) F(A, X)MAP_1_43(F, A, __VA_ARGS__)
#define MAP_1_45(F, A, X, ...) F(A, X)MAP_1_44(F, A, __VA_ARGS__)
#define MAP_1_46(F, A, X, ...) F(A, X)MAP_1_45(F, A, __VA_ARGS__)
#define MAP_1_47(F, A, X, ...) F(A, X)MAP_1_46(F, A, __VA_ARGS__)
#define MAP_1_48(F, A, X, ...) F(A, X)MAP_1_47(F, A, __VA_ARGS__)
#define MAP_1_49(F, A, X, ...) F(A, X)MAP_1_48(F, A, __VA_ARGS__)
#define MAP_1_50(F, A, X, ...) F(A, X)MAP_1_49(F, A, __VA_ARGS__)
#define MAP_1_51(F, A, X, ...) F(A, X)MAP_1_50(F, A, __VA_ARGS__)
#define MAP_1_52(F, A, X, ...) F(A, X)MAP_1_51(F, A, __VA_ARGS__)
#define MAP_1_53(F, A, X, ...) F(A, X)MAP_1_52(F, A, __VA_ARGS__)
#define MAP_1_54(F, A, X, ...) F(A, X)MAP_1_53(F, A, __VA_ARGS__)
#define MAP_1_55(F, A, X, ...) F(A, X)MAP_1_54(F, A, __VA_ARGS__)
#define MAP_1_56(F, A, X, ...) F(A, X)MAP_1_55(F, A, __VA_ARGS__)
#define MAP_1_57(F, A, X, ...) F(A, X)MAP_1_56(F, A, __VA_ARGS__)
#define MAP_1_58(F, A, X, ...) F(A, X)MAP_1_57(F, A, __VA_ARGS__)
#define MAP_1_59(F, A, X, ...) F(A, X)MAP_1_58(F, A, __VA_ARGS__)
#define MAP_1_60(F, A, X, ...) F(A, X)MAP_1_59(F, A, __VA_ARGS__)
#define MAP_1_61(F, A, X, ...) F(A, X)MAP_1_60(F, A, __VA_ARGS__)
#define MAP_1_62(F, A, X, ...) F(A, X)MAP_1_61(F, A, __VA_ARGS__)
#define MAP_1_63(F, A, X, ...) F(A, X)MAP_1_62(F, A, __VA_ARGS__)
#define MAP_1_64(F, A, X, ...) F(A, X)MAP_1_63(F, A, __VA_ARGS__)
#define MAP_1_65(F, A, X, ...) F(A, X)MAP_1_64(F, A, __VA_ARGS__)
#define MAP_1_66(F, A, X, ...) F(A, X)MAP_1_65(F, A, __VA_ARGS__)
#define MAP_1_67(F, A, X, ...) F(A, X)MAP_1_66(F, A, __VA_ARGS__)
#define MAP_1_68(F, A, X, ...) F(A, X)MAP_1_67(F, A, __VA_ARGS__)
#define MAP_1_69(F, A, X, ...) F(A, X)MAP_1_68(F, A, __VA_ARGS__)
#define MAP_1_70(F, A, X, ...) F(A, X)MAP_1_69(F, A, __VA_ARGS__)
#define MAP_1_71(F, A, X, ...) F(A, X)MAP_1_70(F, A, __VA_ARGS__)
#define MAP_1_72(F, A, X, ...) F(A, X)MAP_1_71(F, A, __VA_ARGS__)
#define MAP_1_73(F, A, X, ...) F(A, X)MAP_1_72(F, A, __VA_ARGS__)
#define MAP_1_74(F, A, X, ...) F(A, X)MAP_1_73(F, A, __VA_ARGS__)
#define MAP_1_75(F, A, X, ...) F(A, X)MAP_1_74(F, A, __VA_ARGS__)
#define MAP_1_76(F, A, X, ...) F(A, X)MAP_1_75(F, A, __VA_ARGS__)
#define MAP_1_77(F, A, X, ...) F(A, X)MAP_1_76(F, A, __VA_ARGS__)
#define MAP_1_78(F, A, X, ...) F(A, X)MAP_1_77(F, A, __VA_ARGS__)
#define MAP_1_79(F, A, X, ...) F(A, X)MAP_1_78(F, A, __VA_ARGS__)
#define MAP_1_80(F, A, X, ...) F(A, X)MAP_1_79(F, A, __VA_ARGS__)
#define MAP_1_81(F, A, X, ...) F(A, X)MAP_1_80(F, A, __VA_ARGS__)
#define MAP_1_82(F, A, X, ...) F(A, X)MAP_1_81(F, A, __VA_ARGS__)
#define MAP_1_83(F, A, X, ...) F(A, X)MAP_1_82(F, A, __VA_ARGS__)
#define MAP_1_84(F, A, X, ...) F(A, X)MAP_1_83(F, A, __VA_ARGS__)
#define MAP_1_85(F, A, X, ...) F(A, X)MAP_1_84(F, A, __VA_ARGS__)
#define MAP_1_86(F, A, X, ...) F(A, X)MAP_1_85(F, A, __VA_ARGS__)
#define MAP_1_87(F, A, X, ...) F(A, X)MAP_1_86(F, A, __VA_ARGS__)
#define MAP_1_88(F, A, X, ...) F(A, X)MAP_1_87(F, A, __VA_ARGS__)
#define MAP_1_89(F, A, X, ...) F(A, X)MAP_1_88(F, A, __VA_ARGS__)
#define MAP_1_90(F, A, X, ...) F(A, X)MAP_1_89(F, A, __VA_ARGS__)
#define MAP_1_91(F, A, X, ...) F(A, X)MAP_1_90(F, A, __VA_ARGS__)
#define MAP_1_92(F, A, X, ...) F(A, X)MAP_1_91(F, A, __VA_ARGS__)
#define MAP_1_93(F, A, X, ...) F(A, X)MAP_1_92(F, A, __VA_ARGS__)
#define MAP_1_94(F, A, X, ...) F(A, X)MAP_1_93(F, A, __VA_ARGS__)
#define MAP_1_95(F, A, X, ...) F(A, X)MAP_1_94(F, A, __VA_ARGS__)
#define MAP_1_96(F, A, X, ...) F(A, X)MAP_1_95(F, A, __VA_ARGS__)
// Uses the sliding pairs dispatch technique: by passing __VA_ARGS__ as the
// first set of variables and appending (reverse orderred) names of the
// corresponding macros, we get the name of the correct arity macro.
//
// Ensure this is called with at least N+2 parameters otherwise GCC in
// particular will complain about requiring at least one value for varargs
#define ARITY_DISPATCH( \
_01,_02,_03,_04,_05,_06,_07,_08, \
_09,_10,_11,_12,_13,_14,_15,_16, \
_17,_18,_19,_20,_21,_22,_23,_24, \
_25,_26,_27,_28,_29,_30,_31,_32, \
_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48, \
_49,_50,_51,_52,_53,_54,_55,_56, \
_57,_58,_59,_60,_61,_62,_63,_64, \
_65,_66,_67,_68,_69,_70,_71,_72, \
_73,_74,_75,_76,_77,_78,_79,_80, \
_81,_82,_83,_84,_85,_86,_87,_88, \
_89,_90,_91,_92,_93,_94,_95,_96, \
NAME,... \
) NAME
// Map a macro across __VA_ARGS__. Can be easily expanded, but has non-obvious
// failure mode when supported arity is exceeded.
//
// Don't use this, unless you really need the stringize operator, or other
// macro magic.
//
// Just use templates. Really...
#define MAP(FUNC,...) \
ARITY_DISPATCH(__VA_ARGS__, \
MAP_0_96, MAP_0_95, MAP_0_94, MAP_0_93, MAP_0_92, MAP_0_91, MAP_0_90, MAP_0_89, \
MAP_0_88, MAP_0_87, MAP_0_86, MAP_0_85, MAP_0_84, MAP_0_83, MAP_0_82, MAP_0_81, \
MAP_0_80, MAP_0_79, MAP_0_78, MAP_0_77, MAP_0_76, MAP_0_75, MAP_0_74, MAP_0_73, \
MAP_0_72, MAP_0_71, MAP_0_70, MAP_0_69, MAP_0_68, MAP_0_67, MAP_0_66, MAP_0_65, \
MAP_0_64, MAP_0_63, MAP_0_62, MAP_0_61, MAP_0_60, MAP_0_59, MAP_0_58, MAP_0_57, \
MAP_0_56, MAP_0_55, MAP_0_54, MAP_0_53, MAP_0_52, MAP_0_51, MAP_0_50, MAP_0_49, \
MAP_0_48, MAP_0_47, MAP_0_46, MAP_0_45, MAP_0_44, MAP_0_43, MAP_0_42, MAP_0_41, \
MAP_0_40, MAP_0_39, MAP_0_38, MAP_0_37, MAP_0_36, MAP_0_35, MAP_0_34, MAP_0_33, \
MAP_0_32, MAP_0_31, MAP_0_30, MAP_0_29, MAP_0_28, MAP_0_27, MAP_0_26, MAP_0_25, \
MAP_0_24, MAP_0_23, MAP_0_22, MAP_0_21, MAP_0_20, MAP_0_19, MAP_0_18, MAP_0_17, \
MAP_0_16, MAP_0_15, MAP_0_14, MAP_0_13, MAP_0_12, MAP_0_11, MAP_0_10, MAP_0_09, \
MAP_0_08, MAP_0_07, MAP_0_06, MAP_0_05, MAP_0_04, MAP_0_03, MAP_0_02, MAP_0_01, \
STATIC_ASSERT("invalid arity for MAP") \
)(FUNC, __VA_ARGS__)
// Note: this is one fewer argument than MAP because of the leading parameter
// passed to all invokations.
#define MAP1(FUNC,...) \
ARITY_DISPATCH(__VA_ARGS__, \
MAP_1_95, MAP_1_94, MAP_1_93, MAP_1_92, MAP_1_91, MAP_1_90, MAP_1_89, \
MAP_1_88, MAP_1_87, MAP_1_86, MAP_1_85, MAP_1_84, MAP_1_83, MAP_1_82, MAP_1_81, \
MAP_1_80, MAP_1_79, MAP_1_78, MAP_1_77, MAP_1_76, MAP_1_75, MAP_1_74, MAP_1_73, \
MAP_1_72, MAP_1_71, MAP_1_70, MAP_1_69, MAP_1_68, MAP_1_67, MAP_1_66, MAP_1_65, \
MAP_1_64, MAP_1_63, MAP_1_62, MAP_1_61, MAP_1_60, MAP_1_59, MAP_1_58, MAP_1_57, \
MAP_1_56, MAP_1_55, MAP_1_54, MAP_1_53, MAP_1_52, MAP_1_51, MAP_1_50, MAP_1_49, \
MAP_1_48, MAP_1_47, MAP_1_46, MAP_1_45, MAP_1_44, MAP_1_43, MAP_1_42, MAP_1_41, \
MAP_1_40, MAP_1_39, MAP_1_38, MAP_1_37, MAP_1_36, MAP_1_35, MAP_1_34, MAP_1_33, \
MAP_1_32, MAP_1_31, MAP_1_30, MAP_1_29, MAP_1_28, MAP_1_27, MAP_1_26, MAP_1_25, \
MAP_1_24, MAP_1_23, MAP_1_22, MAP_1_21, MAP_1_20, MAP_1_19, MAP_1_18, MAP_1_17, \
MAP_1_16, MAP_1_15, MAP_1_14, MAP_1_13, MAP_1_12, MAP_1_11, MAP_1_10, MAP_1_09, \
MAP_1_08, MAP_1_07, MAP_1_06, MAP_1_05, MAP_1_04, MAP_1_03, MAP_1_02, MAP_1_01, \
STATIC_ASSERT("invalid arity for MAP1") \
)(FUNC, __VA_ARGS__)
#define LITERAL_00 0
#define LITERAL_01 1
#define LITERAL_02 2
#define LITERAL_03 3
#define LITERAL_04 4
#define LITERAL_05 5
#define LITERAL_06 6
#define LITERAL_07 7
#define LITERAL_08 8
#define LITERAL_09 9
#define LITERAL_10 10
#define LITERAL_11 11
#define LITERAL_12 12
#define LITERAL_13 13
#define LITERAL_14 14
#define LITERAL_15 15
#define LITERAL_16 16
#define LITERAL_17 17
#define LITERAL_18 18
#define LITERAL_19 19
#define LITERAL_20 20
#define LITERAL_21 21
#define LITERAL_22 22
#define LITERAL_23 23
#define LITERAL_24 24
#define LITERAL_25 25
#define LITERAL_26 26
#define LITERAL_27 27
#define LITERAL_28 28
#define LITERAL_29 29
#define LITERAL_30 30
#define LITERAL_31 31
#define LITERAL_32 32
#define LITERAL_33 33
#define LITERAL_34 34
#define LITERAL_35 35
#define LITERAL_36 36
#define LITERAL_37 37
#define LITERAL_38 38
#define LITERAL_39 39
#define LITERAL_40 40
#define LITERAL_41 41
#define LITERAL_42 42
#define LITERAL_43 43
#define LITERAL_44 44
#define LITERAL_45 45
#define LITERAL_46 46
#define LITERAL_47 47
#define LITERAL_48 48
#define LITERAL_49 49
#define LITERAL_50 50
#define LITERAL_51 51
#define LITERAL_52 52
#define LITERAL_53 53
#define LITERAL_54 54
#define LITERAL_55 55
#define LITERAL_56 56
#define LITERAL_57 57
#define LITERAL_58 58
#define LITERAL_59 59
#define LITERAL_60 60
#define LITERAL_61 61
#define LITERAL_62 62
#define LITERAL_63 63
#define LITERAL_64 64
#define LITERAL_65 65
#define LITERAL_66 66
#define LITERAL_67 67
#define LITERAL_68 68
#define LITERAL_69 69
#define LITERAL_70 70
#define LITERAL_71 71
#define LITERAL_72 72
#define LITERAL_73 73
#define LITERAL_74 74
#define LITERAL_75 75
#define LITERAL_76 76
#define LITERAL_77 77
#define LITERAL_78 78
#define LITERAL_79 79
#define LITERAL_80 80
#define LITERAL_81 81
#define LITERAL_82 82
#define LITERAL_83 83
#define LITERAL_84 84
#define LITERAL_85 85
#define LITERAL_86 86
#define LITERAL_87 87
#define LITERAL_88 88
#define LITERAL_89 89
#define LITERAL_90 90
#define LITERAL_91 91
#define LITERAL_92 92
#define LITERAL_93 93
#define LITERAL_94 94
#define LITERAL_95 95
#define LITERAL_96 96
#define VA_ARGS_COUNT(...) \
ARITY_DISPATCH(__VA_ARGS__, \
LITERAL_96, LITERAL_95, LITERAL_94, LITERAL_93, \
LITERAL_92, LITERAL_91, LITERAL_90, LITERAL_89, \
LITERAL_88, LITERAL_87, LITERAL_86, LITERAL_85, \
LITERAL_84, LITERAL_83, LITERAL_82, LITERAL_81, \
LITERAL_80, LITERAL_79, LITERAL_78, LITERAL_77, \
LITERAL_76, LITERAL_75, LITERAL_74, LITERAL_73, \
LITERAL_72, LITERAL_71, LITERAL_70, LITERAL_69, \
LITERAL_68, LITERAL_67, LITERAL_66, LITERAL_65, \
LITERAL_64, LITERAL_63, LITERAL_62, LITERAL_61, \
LITERAL_60, LITERAL_59, LITERAL_58, LITERAL_57, \
LITERAL_56, LITERAL_55, LITERAL_54, LITERAL_53, \
LITERAL_52, LITERAL_51, LITERAL_50, LITERAL_49, \
LITERAL_48, LITERAL_47, LITERAL_46, LITERAL_45, \
LITERAL_44, LITERAL_43, LITERAL_42, LITERAL_41, \
LITERAL_40, LITERAL_39, LITERAL_38, LITERAL_37, \
LITERAL_36, LITERAL_35, LITERAL_34, LITERAL_33, \
LITERAL_32, LITERAL_31, LITERAL_30, LITERAL_29, \
LITERAL_28, LITERAL_27, LITERAL_26, LITERAL_25, \
LITERAL_24, LITERAL_23, LITERAL_22, LITERAL_21, \
LITERAL_20, LITERAL_19, LITERAL_18, LITERAL_17, \
LITERAL_16, LITERAL_15, LITERAL_14, LITERAL_13, \
LITERAL_12, LITERAL_11, LITERAL_10, LITERAL_09, \
LITERAL_08, LITERAL_07, LITERAL_06, LITERAL_05, \
LITERAL_04, LITERAL_03, LITERAL_02, LITERAL_01, \
STATIC_ASSERT("invalid value for VA_ARGS_COUNT")\
)
#endif

202
preprocessor.py Executable file
View File

@ -0,0 +1,202 @@
#!/usr/bin/python3
import itertools
###############################################################################
def chunks(values, size):
it = iter(values)
item = list(itertools.islice(it, size))
while item:
yield item
item = list(itertools.islice(it, size))
###############################################################################
# Construct a variadic macro of the form:
#
# ARITY_DISPATCH(_0001, _0002, NAME, ...) NAME
#
# Where the numbered arguments is equal to the predefined maximum arity.
def generate_dispatch(num):
values = itertools.chain(
("_%04u" % n for n in range (1, num+1)),
["NAME"]
)
yield "#define ARITY_DISPATCH(\\"
for group in chunks(values, 8):
yield ", ".join(group) + ", \\"
yield "...) NAME"
###############################################################################
# Construct a variadic macro of the form:
#
# define REDUCE_1_0002(F,X,Y) F(X,Y)
# define REDUCE_1_0003(F,X,Y,...) REDUCE_2_0002(F,F(X,Y),__VA_ARGS__)
# define REDUCE_1_0004(F,X,Y,...) REDUCE_2_0003(F,F(X,Y),__VA_ARGS__)
#
# and so on
#
# We do not provide a definition for REDUCE_1_0000 because it does not
# actually reduce anything. Instead we define it as a static_assert to
# simplify the general dispatch generation code.
#
# The macro is defined as if it were arity 1, because the dispatch generation
# code operates in terms of the tail call and offsets the dispatch arguments
# by the arity.
def generate_reduce(num):
yield '#define REDUCE_1_0000(...) STATIC_ASSERT("REDUCE requires at least two arguments")'
yield "#define REDUCE_1_0001(F,X,Y) F(X,Y)"
for n in range(2, num):
yield "#define REDUCE_1_%04u(F,X,Y,...) REDUCE_1_%04u(F,F(X,Y),__VA_ARGS__)" % (n, n - 1)
raise StopIteration
###############################################################################
# Generate a variadic macro of the form:
#
# define MAP_ARITY_0000(F,A,B) F(A,B)
# define MAP_ARITY_0001(F,A,B,...) F(X)(MAP_0000_0000(F,A,B,__VA_ARGS___)
# define MAP_ARITY_0002(F,A,B,...) F(X)(MAP_0000_0001(F,A,B,__VA_ARGS___)
#
# and so on...
#
# Note: the arguments A, B, etc are replaced with a quantity of arguments
# indicated by the `arity' parameter.
def generate_map(num, arity):
args = ",".join("ARG%02u" % n for n in range(arity))
if args:
args += ','
yield "#define MAP_%(arity)u_0001(F,%(args)sX) F(%(args)sX)" % { 'arity': arity, 'args': args }
for n in range(2, num):
yield "#define %(curr)s(F,%(args)sX,...) F(%(args)sX)%(next)s(F,%(args)s__VA_ARGS__)" % {
'curr': 'MAP_%(arity)u_%(index)04u' % { 'arity': arity, 'index': n },
'next': 'MAP_%(arity)u_%(index)04u' % { 'arity': arity, 'index': n - 1 },
'arity': arity,
'args': args,
}
raise StopIteration
##-----------------------------------------------------------------------------
def dispatch(name, num, arity):
yield "#define %(name)s%(arity)u(FUNC,...)\\" % { 'name': name, 'arity': arity }
yield "ARITY_DISPATCH(__VA_ARGS__,\\"
for group in chunks(range(num-arity,0,-1), 4):
yield ",".join (
"%(name)s_%(arity)u_%(n)04u" % {
'name': name,
'arity': arity,
'n': n
} for n in group
) + ",\\"
yield ', STATIC_ASSERT("invalid arity for %s")\\' % name
yield ')(FUNC,__VA_ARGS__)'
###############################################################################
def generate_argcount(num):
yield "#define VA_ARGS_COUNT(...)\\"
yield "ARITY_DISPATCH(__VA_ARGS__,\\"
literals = ",".join(str(n) for n in range(num,0,-1))
for group in chunks(range(num, 0, -1), 4):
yield ", ".join('% 4u' % g for g in group) + ',\\'
yield ', STATIC_ASSERT("invalid value for VA_ARGS_COUNT"))'
###############################################################################
import argparse
##-----------------------------------------------------------------------------
if __name__ == '__main__':
#logging.getLogger().setLevel(logging.INFO)
parser = argparse.ArgumentParser(description='Generate variadic macro functions')
parser.add_argument('dst', type=str, help='the output path for the header')
parser.add_argument('num', type=int, help='the maximum argument count')
args = parser.parse_args()
dst = open(args.dst, 'w')
num = args.num
arity = 3
dst.write("""\
#ifndef CRUFT_UTIL_PREPROCESSOR_HPP
#define CRUFT_UTIL_PREPROCESSOR_HPP
///////////////////////////////////////////////////////////////////////////////
//
// This is autogenerated code, do not modify. Instead, look at preprocessor.py
//
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Here be dragons. For the love of God, only use these macros for token
// pasting applications. Don't judge me...
///////////////////////////////////////////////////////////////////////////////
// Token concatenation wrapper that prevents macro expansion. You should not
// be using this outside of this header file (and probably not even then for
// the most part).
#define PASTE_DETAIL(x, y) x##y
// A token concatenation wrapper. You should prefer PASTE over PASTE2. This
// is defined purely so that PASTE (defined laterR) has something to give
// REDUCE1.
#define PASTE2(x,y) PASTE_DETAIL(x,y)
// Pair token concatenation with a trailing comma.
#define PASTE_LIST(x,y) PASTE2(x,y),
// Pair token concatenation, transforming into a namespace and type.
#define NAMESPACE_LIST(NS,KLASS) NS::KLASS,
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
#define STRINGIZE_LIST(x) STRINGIZE(x),
#define STATIC_ASSERT(MSG) static_assert(false, MSG);
///////////////////////////////////////////////////////////////////////////////
""")
dst.write("#define MAX_VA_DISPATCH_ARGS %u\n" % num)
dst.write("#define MAX_VA_DISPATCH_ARITY %u\n" % arity)
lines = itertools.chain (
generate_dispatch(num),
generate_map(num, 0),
generate_map(num, 1),
generate_map(num, 2),
dispatch("MAP", num, 0),
dispatch("MAP", num, 1),
dispatch("MAP", num, 2),
generate_reduce(num),
dispatch("REDUCE", num, 1),
[ "#define PASTE(...) REDUCE1(PASTE2,__VA_ARGS__)" ],
generate_argcount(num)
)
for l in lines:
dst.write(l)
dst.write('\n')
dst.writelines("#endif\n")

View File

@ -11,77 +11,69 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
* Copyright 2016-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_RANDOM_HPP
#define __UTIL_RANDOM_HPP
#ifndef CRUFT_UTIL_RANDOM_HPP
#define CRUFT_UTIL_RANDOM_HPP
#include <algorithm>
#include <random>
#include <limits>
///////////////////////////////////////////////////////////////////////////////
namespace util::rand {
//-------------------------------------------------------------------------
using default_generator = std::minstd_rand;
//-------------------------------------------------------------------------
template <typename Generator = default_generator>
Generator&
thread_engine (void)
namespace util::random {
///////////////////////////////////////////////////////////////////////////
/// return correctly initialised thread-local generator of an unspecified,
/// but not entirely useless, type. ie, not LCG.
inline auto&
generator (void)
{
std::random_device rd;
thread_local Generator gen (rd ());
static thread_local std::mt19937_64 gen { std::random_device {}() };
return gen;
}
//-------------------------------------------------------------------------
template <typename Generator = default_generator, typename T, size_t N>
T&
choose (T (&t)[N], Generator gen = thread_engine<Generator> ())
///////////////////////////////////////////////////////////////////////////
/// select a value uniformly from the range [lo, hi)
template <typename T>
std::enable_if_t<std::is_floating_point_v<T>,T>
uniform (T lo, T hi)
{
std::uniform_int_distribution<size_t> dist (0, N-1);
return t[dist (gen)];
return std::uniform_real_distribution<T> { lo, hi } (generator ());
}
//-------------------------------------------------------------------------
template <
typename T,
typename IteratorT,
typename GeneratorT = default_generator
>
void
uniform (T lo, T hi, IteratorT first, IteratorT last)
/// select a value uniformly from the range [lo, hi)
template <typename T>
std::enable_if_t<std::is_integral_v<T>,T>
uniform (T lo, T hi)
{
static_assert (std::is_same_v<T, typename std::iterator_traits<IteratorT>::value_type>);
auto &gen = thread_engine<GeneratorT> ();
return std::uniform_int_distribution<T> { lo, hi } (generator ());
}
static_assert (std::is_integral_v<T> || std::is_floating_point_v<T>);
if constexpr (std::is_integral_v<T>) {
std::generate (
first,
last,
[&gen, d = std::uniform_int_distribution<T> (lo, hi)]
{
return d (gen);
});
}
///////////////////////////////////////////////////////////////////////////
template <typename T>
std::enable_if_t<std::is_integral_v<T>,T>
uniform (void)
{
return uniform (
std::numeric_limits<T>::min (),
std::numeric_limits<T>::max ()
);
}
if constexpr (std::is_floating_point_v<T>) {
auto d = std::uniform_real_distribution<T> (lo, hi);
std::generate (
first,
last,
[&]
{
return d (gen);
});
}
///////////////////////////////////////////////////////////////////////////
/// choose a value at random from an array
template <typename T, size_t N>
T&
choose (T (&t)[N])
{
std::uniform_int_distribution<size_t> dist (0, N - 1);
return t[dist (generator ())];
}
};

View File

@ -204,14 +204,16 @@ namespace util {
//-----------------------------------------------------------------------------
namespace util {
template struct range<double>;
template struct range<float>;
template struct range<uint8_t>;
template struct range<uint16_t>;
template struct range<uint32_t>;
template struct range<uint64_t>;
}
template struct util::range<double>;
template struct util::range<float>;
template struct util::range<int8_t>;
template struct util::range<int16_t>;
template struct util::range<int32_t>;
template struct util::range<int64_t>;
template struct util::range<uint8_t>;
template struct util::range<uint16_t>;
template struct util::range<uint32_t>;
template struct util::range<uint64_t>;
//-----------------------------------------------------------------------------

View File

@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2010-2016 Danny Robson <danny@nerdcruft.net>
* Copyright 2010-2017 Danny Robson <danny@nerdcruft.net>
*/
@ -23,6 +23,8 @@
#include <array>
using util::region;
//-----------------------------------------------------------------------------
template <size_t S, typename T>
@ -50,19 +52,15 @@ util::region<S,T>::region (point_t _a,
point_t _b):
region (_a, extent_t { _b - _a })
{
// This check must allow for zero area (but non-zero dimension) regions.
// Some code paths need to support this degenerate case. It's ugly but
// simplifies generalisation. eg, vertical linear bezier curves.
CHECK (all (_a <= _b));
debug::sanity (*this);
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>::region (std::array<T,S*2> args)
{
std::copy (&args[0], &args[S], p.data);
std::copy (&args[S], &args[S*2], e.data);
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
T
@ -100,17 +98,6 @@ util::region<S,T>::magnitude (extent_t _e)
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
void
util::region<S,T>::scale (T factor)
{
auto o = (e * factor - e) / T(2);
p -= o;
e *= factor;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
bool
@ -163,32 +150,6 @@ util::region<S,T>::closest (point_t q) const
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
bool
util::region<S,T>::includes (point_t q) const
{
for (size_t i = 0; i < S; ++i)
if (q[i] < p[i] || q[i] > p[i] + e[i])
return false;
return true;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
bool
util::region<S,T>::contains (point_t q) const
{
for (size_t i = 0; i < S; ++i)
if (q[i] <= p[i] || q[i] >= p[i] + e[i])
return false;
return true;
}
//-----------------------------------------------------------------------------
// FIXME: This will fail with an actual infinite range (NaNs will be generated
// in the conditionals).
@ -197,7 +158,7 @@ bool
util::region<S,T>::intersects (region<S,T> rhs) const
{
for (size_t i = 0; i < S; ++i)
if (p[i] >= rhs.p[i] + rhs.e[i] ||
if ( p[i] >= rhs.p[i] + rhs.e[i] ||
rhs.p[i] >= p[i] + e[i])
{ return false; }
@ -207,20 +168,11 @@ util::region<S,T>::intersects (region<S,T> rhs) const
//-----------------------------------------------------------------------------
template <size_t S, typename T>
void
util::region<S,T>::constrain (point_t &q) const
typename region<S,T>::point_t
region<S,T>::constrain (point_t q) const noexcept
{
for (size_t i = 0; i < S; ++i)
q[i] = limit (q[i], p[i], p[i] + e[i]);
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
typename util::region<S,T>::point_t
util::region<S,T>::constrained (point_t q) const
{
constrain (q);
return q;
}
@ -247,53 +199,41 @@ util::region<S,T>::intersection (region<S,T> rhs) const
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>&
util::region<S,T>::resize (extent<S,T> _e)
bool
util::region<S,T>::covers (region<S, T> r) const noexcept
{
e = _e;
return *this;
return all (p <= r.p) && all (p + e >= r.p + r.e);
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
util::region<S,T>
util::region<S,T>::inset (T mag) const
{
return inset (util::vector<S,T> {mag});
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>
util::region<S,T>::inset (T mag)
util::region<S,T>::inset (vector<S,T> mag) const
{
// ensure we have enough space to inset
CHECK (min (e) >= 2 * mag);
// ensure we have enough space to trim off our total extent
CHECK (all (e >= T{2} * mag));
return {
p + mag,
e - static_cast<T> (2 * mag)
p + mag,
e - T{2} * mag
};
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>&
util::region<S,T>::expand (vector<S,T> v)
{
p -= v;
e += v * T{2};
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>&
util::region<S,T>::expand (T mag)
{
return expand (vector<S,T> {mag});
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>
util::region<S,T>::expanded (vector<S,T> v) const
util::region<S,T>::expand (vector<S,T> v) const
{
return {
p - v,
@ -305,9 +245,9 @@ util::region<S,T>::expanded (vector<S,T> v) const
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::region<S,T>
util::region<S,T>::expanded (T mag) const
util::region<S,T>::expand (T mag) const
{
return expanded (vector<S,T> {mag});
return expand (vector<S,T> {mag});
}

View File

@ -11,17 +11,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2010-2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2010-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_REGION_HPP
#define __UTIL_REGION_HPP
#ifndef CRUFT_UTIL_REGION_HPP
#define CRUFT_UTIL_REGION_HPP
#include "extent.hpp"
#include "point.hpp"
#include "vector.hpp"
#include "types/traits.hpp"
#include "./extent.hpp"
#include "./point.hpp"
#include "./vector.hpp"
#include "./types/traits.hpp"
#include <ostream>
@ -48,7 +48,6 @@ namespace util {
explicit region (extent_t);
region (point_t, extent_t);
region (point_t, point_t);
explicit region (std::array<T,S*2>);
//---------------------------------------------------------------------
template <typename U>
@ -60,8 +59,6 @@ namespace util {
extent_t magnitude (void) const;
extent_t magnitude (extent_t);
void scale (T factor);
bool empty (void) const;
//---------------------------------------------------------------------
@ -71,29 +68,41 @@ namespace util {
point_t closest (point_t) const;
//---------------------------------------------------------------------
// Point and region relation queries
bool includes (point_t) const; // inclusive of borders
bool contains (point_t) const; // exclusive of borders
bool intersects (region<S,T>) const; // exclusive of borders
// Move a point to be within the region bounds
void constrain (point_t&) const;
point_t constrained (point_t) const;
// exclusive of borders
bool intersects (region<S,T>) const;
// Compute binary region combinations
region intersection (region<S,T>) const;
// Test if a region lies completely within our space
bool covers (region<S,T>) const noexcept;
/// Test if a point lies within our space. Inclusive of borders
constexpr
bool
inclusive (point<S,T> q) const noexcept
{
return all (p <= q && p + e >= q);
}
/// test if a point lies within our space, exclusive of the
/// bottom-right border
constexpr bool
exclusive (point<S,T> q) const noexcept
{
return all (p <= q && p + e > q);
}
// Move a point to be within the region bounds
point_t constrain (point_t) const noexcept;
//---------------------------------------------------------------------
region& resize (extent<S,T>);
// Compute a region `mag` units into the region
region inset (T mag);
region inset (T mag) const;
region inset (vector<S,T> mag) const;
region expanded (T mag) const;
region expanded (vector<S,T>) const;
region& expand (T mag);
region& expand (vector<S,T>);
region expand (T mag) const;
region expand (vector<S,T>) const;
// arithmetic operators
region operator+ (vector<S,T>) const;
@ -108,9 +117,108 @@ namespace util {
static constexpr region<S,T> max (void);
static constexpr region<S,T> unit (void);
static constexpr region<S,T> zero (void)
{ return { point_t {0}, extent_t {0} }; }
void sanity (void) const;
};
///////////////////////////////////////////////////////////////////////////
/// constructs the minimal region that encompasses a region and a point.
template <typename T, size_t S>
region<S,T>
make_union (region<S,T> r, point<S,T> p)
{
const auto p0 = select (r.p < p, r.p, p);
const auto p1 = select (r.away () > p, r.away (), p);
return { p0, p1 };
}
///////////////////////////////////////////////////////////////////////////
/// construct a point iterator across a given region, generating each
/// valid point in row-major sequence.
///
/// this is only defined for integral types as it's not clear how to
/// handle floats; it's _super_ unlikely anyone actually wants to visit
/// every single floating point value for a region (and if so they can
/// damn well code that monstrosity themselves).
template <
typename T,
std::size_t S,
typename = std::enable_if_t<
std::is_integral_v<T>, void
>
>
auto
make_range (region<S,T> r)
{
using region_t = region<S,T>;
using point_t = typename region_t::point_t;
using vector_t = util::vector<S,T>;
// this range object is mostly a wrapper around the existing
// extent_range object with a constant offset. it's not going to be as
// performant, but when we discover this is an issue we can do write a
// better version of this object & iterator.
class region_range {
public:
class iterator : public std::iterator<std::forward_iterator_tag, point_t, size_t> {
public:
iterator (typename extent_range<S,T>::iterator _inner, vector_t _offset):
m_inner (_inner),
m_offset (_offset)
{ ; }
point_t operator* (void) const { return *m_inner + m_offset; }
iterator&
operator++ (void)
{
++m_inner;
return *this;
}
bool operator== (const iterator &rhs) const
{
assert (m_offset == rhs.m_offset);
return m_inner == rhs.m_inner;
}
bool operator!= (const iterator &rhs) const
{ return !(*this == rhs); }
private:
typename extent_range<S,T>::iterator m_inner;
vector_t m_offset;
};
region_range (region_t _r):
m_range { _r.e + T{1} },
m_offset { _r.p.template as<util::vector> () }
{ ; }
iterator begin (void) const { return { m_range.begin (), m_offset }; }
iterator end (void) const { return { m_range.end (), m_offset }; }
iterator cbegin (void) const { return begin (); }
iterator cend (void) const { return end (); }
private:
const extent_range<S,T> m_range;
const vector_t m_offset;
};
return region_range { r };
};
template <typename T> using region2 = region<2,T>;
template <typename T> using region3 = region<3,T>;

View File

@ -32,7 +32,7 @@ namespace util {
R operator() (T first, T last, Args&&... args)
{
while (first != last)
if (!(*first++)(std::forward<Args> (args)...))
if (!(*first++)(args...))
return false;
return true;
@ -47,7 +47,7 @@ namespace util {
R operator() (T first, T last, Args&&... args)
{
while (first != last)
if ((*first++)(std::forward<Args> (args)...))
if ((*first++)(args...))
return true;
return false;
@ -62,7 +62,7 @@ namespace util {
R operator() (T first, T last, Args&&... args)
{
while (first != last) {
(*first++)(std::forward<Args> (args)...);
(*first++)(args...);
}
}
};
@ -81,8 +81,8 @@ namespace util {
~signal ();
/// Add a callback to list.
cookie connect (callback&&);
cookie connect (const callback&);
cookie connect [[gnu::warn_unused_result]] (callback&&);
cookie connect [[gnu::warn_unused_result]] (const callback&);
void disconnect (cookie&);

View File

@ -165,20 +165,12 @@ namespace util {
if (m_children.empty ())
return R();
//auto i = m_children.cbegin ();
//bool looping;
C<F> combiner;
return combiner (m_children.begin (), m_children.end (), std::forward<Args> (tail)...);
//do {
// // Increment before we execute so that the caller is able to
// // deregister themselves during execution.
// auto current = i++;
// looping = m_children.cend () != i;
// (*current)(std::forward<Args> (tail)...);
//} while (looping);
return combiner (
m_children.begin (),
m_children.end (),
std::forward<Args> (tail)...
);
}

View File

@ -11,11 +11,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2011-2016 Danny Robson <danny@nerdcruft.net>
* Copyright 2011-2017 Danny Robson <danny@nerdcruft.net>
*/
#include "string.hpp"
#include "./debug.hpp"
#include <cstring>
#include <codecvt>
#include <locale>

View File

@ -40,7 +40,20 @@ namespace util {
tokeniser (Iterator first, Iterator last, value_type separator);
struct iterator {
template <typename ContainerT>
tokeniser (ContainerT &container, typename ContainerT::value_type _separator):
tokeniser (
std::begin (container),
std::end (container),
_separator
)
{ ; }
struct iterator : public std::iterator<
std::forward_iterator_tag,
range_type,
std::size_t
> {
public:
iterator operator++ (int);
iterator& operator++ (void)&;
@ -71,10 +84,29 @@ namespace util {
const value_type m_separator;
};
tokeniser<std::string::const_iterator> make_tokeniser (const std::string&, std::string::value_type);
tokeniser<std::string::const_iterator> make_tokeniser (std::string&&, std::string::value_type) = delete;
tokeniser<const char*> make_tokeniser (const char*, char);
///////////////////////////////////////////////////////////////////////////
template <typename CharT, std::size_t LengthV>
auto
make_tokeniser (CharT (&data)[LengthV], CharT separator)
{
return tokeniser { std::begin (data), std::end (data), separator };
}
//-------------------------------------------------------------------------
tokeniser<std::string::const_iterator>
make_tokeniser (const std::string&, std::string::value_type);
//-------------------------------------------------------------------------
tokeniser<std::string::const_iterator>
make_tokeniser (std::string&&, std::string::value_type) = delete;
//-------------------------------------------------------------------------
tokeniser<const char*>
make_tokeniser (const char*, char);
}

View File

@ -73,6 +73,12 @@ namespace util { namespace TAP {
void expect_throw (T&&, const char (&fmt)[N], Args&&...);
//---------------------------------------------------------------------
template <size_t N, typename ...Args>
void fail (const char (&fmt)[N], Args &&...args)
{
expect (false, fmt, std::forward<Args> (args)...);
}
void skip (const std::string &msg);
void todo (const std::string &msg);
void noop (void);

View File

@ -1,7 +1,7 @@
#include "tap.hpp"
#include "alloc/aligned.hpp"
#include "alloc/linear.hpp"
#include "alloc/raw/aligned.hpp"
#include "alloc/raw/linear.hpp"
int
@ -20,7 +20,7 @@ main (int, char**)
// we're probably operating correctly.
static constexpr std::size_t alignment = 3;
util::alloc::aligned<util::alloc::linear> alloc (
util::alloc::raw::aligned<util::alloc::raw::linear> alloc (
alignment, std::begin (buffer), std::end (buffer)
);

View File

@ -1,11 +1,13 @@
#include "tap.hpp"
#include "alloc/arena.hpp"
#include "alloc/linear.hpp"
#include "alloc/raw/linear.hpp"
///////////////////////////////////////////////////////////////////////////////
static char g_backing[1024*1024];
//-----------------------------------------------------------------------------
struct setter {
setter (const setter&) = delete;
@ -20,11 +22,12 @@ struct setter {
};
//-----------------------------------------------------------------------------
int
main (void)
{
util::alloc::linear alloc (std::begin (g_backing), std::end (g_backing));
util::alloc::arena<util::alloc::linear> arena (alloc);
util::alloc::raw::linear alloc (std::begin (g_backing), std::end (g_backing));
util::alloc::arena<util::alloc::raw::linear> arena (alloc);
util::TAP::logger tap;

View File

@ -1,14 +1,15 @@
#include "tap.hpp"
#include "alloc/dynamic.hpp"
#include "alloc/null.hpp"
#include "alloc/raw/dynamic.hpp"
#include "alloc/raw/null.hpp"
///////////////////////////////////////////////////////////////////////////////
int
main (void)
{
util::TAP::logger tap;
auto obj = util::alloc::dynamic::make<util::alloc::null> ();
auto obj = util::alloc::raw::dynamic::make<util::alloc::raw::null> ();
tap.expect_throw<std::bad_alloc> (
[&] (void) {

View File

@ -1,7 +1,8 @@
#include "tap.hpp"
#include "alloc/linear.hpp"
#include "alloc/raw/linear.hpp"
///////////////////////////////////////////////////////////////////////////////
int
main (void)
{
@ -10,9 +11,9 @@ main (void)
constexpr size_t BUFFER_SIZE = 1024;
alignas (std::max_align_t) char memory[BUFFER_SIZE];
util::alloc::linear store (std::begin (memory), std::end (memory));
util::alloc::raw::linear store (std::begin (memory), std::end (memory));
tap.expect_eq (store.base (), std::begin (memory), "base pointers match");
tap.expect_eq (store.begin (), std::begin (memory), "base pointers match");
tap.expect_eq (store.offset (std::begin (memory)), 0u, "base offset is 0");
tap.expect_eq (store.capacity (), BUFFER_SIZE, "bytes capacity matches");

View File

@ -1,10 +1,10 @@
#include "tap.hpp"
#include "alloc/stack.hpp"
#include "alloc/raw/stack.hpp"
///////////////////////////////////////////////////////////////////////////////
void
n_allocations (util::alloc::stack &store,
n_allocations (util::alloc::raw::stack &store,
unsigned count,
size_t bytes,
size_t alignment = alignof (std::max_align_t))
@ -32,9 +32,9 @@ main (void)
alignas (std::max_align_t) char memory[BUFFER_SIZE];
std::fill (std::begin (memory), std::end (memory), 0);
util::alloc::stack store (memory, memory + BUFFER_AVAILABLE);
util::alloc::raw::stack store (memory, memory + BUFFER_AVAILABLE);
tap.expect_eq (store.base (), std::begin (memory), "base pointers match");
tap.expect_eq (store.begin (), std::begin (memory), "base pointers match");
tap.expect_eq (store.offset (std::begin (memory)), 0u, "base offset is 0");
tap.expect_eq (store.capacity (), BUFFER_AVAILABLE, "bytes capacity matches");

View File

@ -23,13 +23,6 @@ main (void)
tap.expect_eq (-p, util::point2i { 1, -2 }, "unary point negation");
tap.expect_eq ( p, p, "unary point addition");
tap.expect (
std::is_same<
bool,
decltype(!p)::value_type
>::value,
"unary point boolean negation has type bool"
);
auto vec = util::vector4f (0.5f);
tap.expect_eq (vec, util::normalised (vec), "normalisation of normalised vector");
@ -42,6 +35,7 @@ main (void)
tap.expect (x == p.x && y == p.y, "structured bindings extract correct data");
}
// ensure the distance function behaves correctly with non-normal numbers.
{
util::point3f a { 103, 0, 14 };
util::point3f b { 104, INFINITY, 15 };
@ -53,5 +47,62 @@ main (void)
);
}
// test expected outputs for various vector-logical operations
{
constexpr util::point3i a { 0, -1, 2 };
constexpr util::point3i b { 0, 1, -2 };
constexpr util::point3i c { -9, -9, -9 };
tap.expect (!all (a <= b), "all, expected failure");
tap.expect ( all (a <= a), "all, expected success");
tap.expect (!any (a <= c), "any, expected failure");
tap.expect ( any (a <= b), "any, expected success");
};
// ensure the util::select function behaves as expected
{
const util::point3f a { -1, 2, 0 };
const util::point3f b { 1, 0, 2 };
const util::point3f lo { -1, 0, 0 };
const util::point3f hi { 1, 2, 2 };
tap.expect_eq (select (a < b, a, b), lo, "select with points and min");
tap.expect_eq (select (a > b, a, b), hi, "select with points and max");
};
// ensure that util::limit resolves to the coord overload. the exact
// values are less useful than exercising the compiler/linker.
{
const util::vector3f val { 0, -1, 2 };
const util::vector3f lo { -1, 1, -2 };
const util::vector3f hi { 1, 2, 0 };
tap.expect_eq (limit (val, lo, hi), util::vector3f { 0, 1, 0 }, "limit with vec/vec/vec");
tap.expect_eq (limit (val, 0.f, hi), util::vector3f { 0, 0, 0 }, "limit with vec/num/vec");
tap.expect_eq (limit (val, lo, 2.f), util::vector3f { 0, 1, 2 }, "limit with vec/vec/num");
tap.expect_eq (limit (val, 0.f, 2.f), util::vector3f { 0, 0, 2 }, "limit with vec/num/num");
}
// ensure that klass::indices appears to link correctly
{
const util::vector3i seq { 0, 1, 2 };
const util::vector4i res { 2, 0, 0, 1 };
tap.expect_eq (seq.indices<2,0,0,1> (), res, "coord::indices expansion");
};
// ensure that util::shift operations appear to operate correctly
{
const util::vector3i seq { 0, 1, 2 };
tap.expect_eq (rshift (seq, 1, 0), util::make_vector (0, 0, 1), "rshift, scalar fill");
tap.expect_eq (
rshift (seq, 2, util::make_vector (3, 4, 5 )),
util::make_vector (3, 4, 0),
"rshift, coord fill"
);
};
return tap.status ();
}

229
test/crypto/salsa.cpp Normal file
View File

@ -0,0 +1,229 @@
#include "crypto/salsa.hpp"
#include "tap.hpp"
///////////////////////////////////////////////////////////////////////////////
void
test_quarter (util::TAP::logger &tap)
{
static const struct {
std::array<uint32_t, 4> a, b;
} TESTS[] = {
{ { 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
{ { 0x00000001, 0x00000000, 0x00000000, 0x00000000 },
{ 0x08008145, 0x00000080, 0x00010200, 0x20500000 } },
{ { 0x00000000, 0x00000001, 0x00000000, 0x00000000 },
{ 0x88000100, 0x00000001, 0x00000200, 0x00402000 } },
{ { 0x00000000, 0x00000000, 0x00000001, 0x00000000 },
{ 0x80040000, 0x00000000, 0x00000001, 0x00002000 } },
{ { 0x00000000, 0x00000000, 0x00000000, 0x00000001 },
{ 0x00048044, 0x00000080, 0x00010000, 0x20100001 } },
{ { 0xe7e8c006, 0xc4f9417d, 0x6479b4b2, 0x68c67137 },
{ 0xe876d72b, 0x9361dfd5, 0xf1460244, 0x948541a3 } },
{ { 0xd3917c5b, 0x55f1c407, 0x52a58a7a, 0x8f887a3b },
{ 0x3e2f308c, 0xd90a8f36, 0x6ab2a923, 0x2883524c } },
};
for (size_t i = 0; i < std::size (TESTS); ++i)
tap.expect_eq (util::crypto::salsa::quarter (TESTS[i].a), TESTS[i].b, "quarter %zu", i);
}
///////////////////////////////////////////////////////////////////////////////
void
test_row (util::TAP::logger &tap)
{
static const struct {
std::array<uint32_t, 16> a, b;
} TESTS[] = {
{ { 0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0x00000000, 0x00000000, 0x00000000, },
{ 0x08008145, 0x00000080, 0x00010200, 0x20500000,
0x20100001, 0x00048044, 0x00000080, 0x00010000,
0x00000001, 0x00002000, 0x80040000, 0x00000000,
0x00000001, 0x00000200, 0x00402000, 0x88000100, }
},
{ { 0x08521bd6, 0x1fe88837, 0xbb2aa576, 0x3aa26365,
0xc54c6a5b, 0x2fc74c2f, 0x6dd39cc3, 0xda0a64f6,
0x90a2f23d, 0x067f95a6, 0x06b35f61, 0x41e4732e,
0xe859c100, 0xea4d84b7, 0x0f619bff, 0xbc6e965a, },
{ 0xa890d39d, 0x65d71596, 0xe9487daa, 0xc8ca6a86,
0x949d2192, 0x764b7754, 0xe408d9b9, 0x7a41b4d1,
0x3402e183, 0x3c3af432, 0x50669f96, 0xd89ef0a8,
0x0040ede5, 0xb545fbce, 0xd257ed4f, 0x1818882d, },
}
};
for (size_t i = 0; i < std::size (TESTS); ++i)
tap.expect_eq (util::crypto::salsa::row (TESTS[i].a), TESTS[i].b, "row %zu", i);
}
///////////////////////////////////////////////////////////////////////////////
void
test_col (util::TAP::logger &tap)
{
static const struct {
std::array<uint32_t,16> a, b;
} TESTS[] = {
{ { 0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000001, 0x00000000, 0x00000000, 0x00000000, },
{ 0x10090288, 0x00000000, 0x00000000, 0x00000000,
0x00000101, 0x00000000, 0x00000000, 0x00000000,
0x00020401, 0x00000000, 0x00000000, 0x00000000,
0x40a04001, 0x00000000, 0x00000000, 0x00000000, } },
{ { 0x08521bd6, 0x1fe88837, 0xbb2aa576, 0x3aa26365,
0xc54c6a5b, 0x2fc74c2f, 0x6dd39cc3, 0xda0a64f6,
0x90a2f23d, 0x067f95a6, 0x06b35f61, 0x41e4732e,
0xe859c100, 0xea4d84b7, 0x0f619bff, 0xbc6e965a, },
{ 0x8c9d190a, 0xce8e4c90, 0x1ef8e9d3, 0x1326a71a,
0x90a20123, 0xead3c4f3, 0x63a091a0, 0xf0708d69,
0x789b010c, 0xd195a681, 0xeb7d5504, 0xa774135c,
0x481c2027, 0x53a8e4b5, 0x4c1f89c5, 0x3f78c9c8, } },
};
for (size_t i = 0; i < std::size (TESTS); ++i)
tap.expect_eq (util::crypto::salsa::col (TESTS[i].a), TESTS[i].b, "col %zu", i);
}
///////////////////////////////////////////////////////////////////////////////
void
test_doubleround (util::TAP::logger &tap)
{
static const struct {
std::array<uint32_t,16> a, b;
} TESTS[] = {
{ { 0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, },
{ 0x8186a22d, 0x0040a284, 0x82479210, 0x06929051,
0x08000090, 0x02402200, 0x00004000, 0x00800000,
0x00010200, 0x20400000, 0x08008104, 0x00000000,
0x20500000, 0xa0000040, 0x0008180a, 0x612a8020, } },
{ { 0xde501066, 0x6f9eb8f7, 0xe4fbbd9b, 0x454e3f57,
0xb75540d3, 0x43e93a4c, 0x3a6f2aa0, 0x726d6b36,
0x9243f484, 0x9145d1e8, 0x4fa9d247, 0xdc8dee11,
0x054bf545, 0x254dd653, 0xd9421b6d, 0x67b276c1, },
{ 0xccaaf672, 0x23d960f7, 0x9153e63a, 0xcd9a60d0,
0x50440492, 0xf07cad19, 0xae344aa0, 0xdf4cfdfc,
0xca531c29, 0x8e7943db, 0xac1680cd, 0xd503ca00,
0xa74b2ad6, 0xbc331c5c, 0x1dda24c7, 0xee928277, } }
};
for (size_t i = 0; i < std::size (TESTS); ++i)
tap.expect_eq (util::crypto::salsa::doubleround (TESTS[i].a), TESTS[i].b, "doubleround %zu", i);
}
///////////////////////////////////////////////////////////////////////////////
void
test_salsa20 (util::TAP::logger &tap)
{
static const struct {
std::array<uint8_t,64> a, b;
} TESTS[] = {
{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
{ { 0xd3, 0x9f, 0x0d, 0x73, 0x4c, 0x37, 0x52, 0xb7,
0x03, 0x75, 0xde, 0x25, 0xbf, 0xbb, 0xea, 0x88,
0x31, 0xed, 0xb3, 0x30, 0x01, 0x6a, 0xb2, 0xdb,
0xaf, 0xc7, 0xa6, 0x30, 0x56, 0x10, 0xb3, 0xcf,
0x1f, 0xf0, 0x20, 0x3f, 0x0f, 0x53, 0x5d, 0xa1,
0x74, 0x93, 0x30, 0x71, 0xee, 0x37, 0xcc, 0x24,
0x4f, 0xc9, 0xeb, 0x4f, 0x03, 0x51, 0x9c, 0x2f,
0xcb, 0x1a, 0xf4, 0xf3, 0x58, 0x76, 0x68, 0x36 },
{ 0x6d, 0x2a, 0xb2, 0xa8, 0x9c, 0xf0, 0xf8, 0xee,
0xa8, 0xc4, 0xbe, 0xcb, 0x1a, 0x6e, 0xaa, 0x9a,
0x1d, 0x1d, 0x96, 0x1a, 0x96, 0x1e, 0xeb, 0xf9,
0xbe, 0xa3, 0xfb, 0x30, 0x45, 0x90, 0x33, 0x39,
0x76, 0x28, 0x98, 0x9d, 0xb4, 0x39, 0x1b, 0x5e,
0x6b, 0x2a, 0xec, 0x23, 0x1b, 0x6f, 0x72, 0x72,
0xdb, 0xec, 0xe8, 0x87, 0x6f, 0x9b, 0x6e, 0x12,
0x18, 0xe8, 0x5f, 0x9e, 0xb3, 0x13, 0x30, 0xca } },
{ { 0x58, 0x76, 0x68, 0x36, 0x4f, 0xc9, 0xeb, 0x4f,
0x03, 0x51, 0x9c, 0x2f, 0xcb, 0x1a, 0xf4, 0xf3,
0xbf, 0xbb, 0xea, 0x88, 0xd3, 0x9f, 0x0d, 0x73,
0x4c, 0x37, 0x52, 0xb7, 0x03, 0x75, 0xde, 0x25,
0x56, 0x10, 0xb3, 0xcf, 0x31, 0xed, 0xb3, 0x30,
0x01, 0x6a, 0xb2, 0xdb, 0xaf, 0xc7, 0xa6, 0x30,
0xee, 0x37, 0xcc, 0x24, 0x1f, 0xf0, 0x20, 0x3f,
0x0f, 0x53, 0x5d, 0xa1, 0x74, 0x93, 0x30, 0x71 },
{ 0xb3, 0x13, 0x30, 0xca, 0xdb, 0xec, 0xe8, 0x87,
0x6f, 0x9b, 0x6e, 0x12, 0x18, 0xe8, 0x5f, 0x9e,
0x1a, 0x6e, 0xaa, 0x9a, 0x6d, 0x2a, 0xb2, 0xa8,
0x9c, 0xf0, 0xf8, 0xee, 0xa8, 0xc4, 0xbe, 0xcb,
0x45, 0x90, 0x33, 0x39, 0x1d, 0x1d, 0x96, 0x1a,
0x96, 0x1e, 0xeb, 0xf9, 0xbe, 0xa3, 0xfb, 0x30,
0x1b, 0x6f, 0x72, 0x72, 0x76, 0x28, 0x98, 0x9d,
0xb4, 0x39, 0x1b, 0x5e, 0x6b, 0x2a, 0xec, 0x23 } }
};
for (size_t i = 0; i < std::size (TESTS); ++i)
tap.expect_eq (util::crypto::salsa20 (TESTS[i].a), TESTS[i].b, "salsa20 %zu", i);
struct {
std::array<uint8_t,64> a, b;
} million = {
{ 0x06, 0x7c, 0x53, 0x92, 0x26, 0xbf, 0x09, 0x32,
0x04, 0xa1, 0x2f, 0xde, 0x7a, 0xb6, 0xdf, 0xb9,
0x4b, 0x1b, 0x00, 0xd8, 0x10, 0x7a, 0x07, 0x59,
0xa2, 0x68, 0x65, 0x93, 0xd5, 0x15, 0x36, 0x5f,
0xe1, 0xfd, 0x8b, 0xb0, 0x69, 0x84, 0x17, 0x74,
0x4c, 0x29, 0xb0, 0xcf, 0xdd, 0x22, 0x9d, 0x6c,
0x5e, 0x5e, 0x63, 0x34, 0x5a, 0x75, 0x5b, 0xdc,
0x92, 0xbe, 0xef, 0x8f, 0xc4, 0xb0, 0x82, 0xba },
{ 0x08, 0x12, 0x26, 0xc7, 0x77, 0x4c, 0xd7, 0x43,
0xad, 0x7f, 0x90, 0xa2, 0x67, 0xd4, 0xb0, 0xd9,
0xc0, 0x13, 0xe9, 0x21, 0x9f, 0xc5, 0x9a, 0xa0,
0x80, 0xf3, 0xdb, 0x41, 0xab, 0x88, 0x87, 0xe1,
0x7b, 0x0b, 0x44, 0x56, 0xed, 0x52, 0x14, 0x9b,
0x85, 0xbd, 0x09, 0x53, 0xa7, 0x74, 0xc2, 0x4e,
0x7a, 0x7f, 0xc3, 0xb9, 0xb9, 0xcc, 0xbc, 0x5a,
0xf5, 0x09, 0xb7, 0xf8, 0xe2, 0x55, 0xf5, 0x68 }
};
for (int i = 0; i < 1'000'000; ++i)
million.a = util::crypto::salsa20 (million.a);
tap.expect_eq (million.a, million.b, "salsa20 million");
}
///////////////////////////////////////////////////////////////////////////////
int
main (void)
{
util::TAP::logger tap;
test_quarter (tap);
test_row (tap);
test_col (tap);
test_doubleround (tap);
test_salsa20 (tap);
return 0;
}

31
test/endian.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "tap.hpp"
#include "endian.hpp"
///////////////////////////////////////////////////////////////////////////////
int
main (void)
{
util::TAP::logger tap;
{
uint32_t a = 0x12345678, b = 0x78563412;
tap.expect_eq (a, util::bswap (b), "u32 byteswap");
}
{
// try to byte swap the pattern for 1.0f
//
// it may not be the most robust test, but it'll catch the most
// egregious errors for the time being.
union {
uint32_t u;
float f;
} data { .u = 0x0000803f /* 0x3f800000 == 1.f */ };
tap.expect_eq (util::bswap (data.f), 1.f, "f32 byteswap");
};
return tap.status ();
}

Some files were not shown because too many files have changed in this diff Show More