Merge branch 'master' into coord
This commit is contained in:
commit
0351313c36
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,6 +17,7 @@
|
||||
Makefile
|
||||
Makefile.in
|
||||
/missing
|
||||
/preprocessor.hpp
|
||||
/stamp-h1
|
||||
/test-driver
|
||||
/uri.cpp
|
||||
|
@ -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
|
||||
|
20
adapter.hpp
20
adapter.hpp
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -1 +0,0 @@
|
||||
#include "fallback.hpp"
|
@ -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;
|
||||
|
@ -16,7 +16,8 @@
|
||||
|
||||
#include "affix.hpp"
|
||||
|
||||
using util::alloc::affix;
|
||||
using util::alloc::raw::affix;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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;
|
||||
};
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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
17
alloc/raw/fallback.cpp
Normal 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"
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
@ -16,11 +16,11 @@
|
||||
|
||||
#include "malloc.hpp"
|
||||
|
||||
#include "../debug.hpp"
|
||||
#include "../../debug.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
using util::alloc::malloc;
|
||||
using util::alloc::raw::malloc;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
@ -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
|
@ -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;
|
||||
}
|
@ -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);
|
@ -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;
|
||||
}
|
@ -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);
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
831
coord/ops.hpp
831
coord/ops.hpp
File diff suppressed because it is too large
Load Diff
@ -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
24
crypto/salsa.cpp
Normal 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
86
crypto/salsa.hpp
Normal 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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
94
debug.hpp
94
debug.hpp
@ -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&);
|
||||
|
33
endian.hpp
33
endian.hpp
@ -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;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -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 };
|
||||
}
|
||||
|
||||
|
||||
|
42
extent.hpp
42
extent.hpp
@ -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>;
|
||||
}
|
||||
|
||||
|
15
extent.ipp
15
extent.ipp
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
@ -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> ();
|
||||
}
|
||||
};
|
||||
}
|
@ -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>);
|
||||
|
@ -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;
|
||||
|
@ -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&
|
||||
|
@ -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 <
|
||||
|
26
geom/ray.cpp
26
geom/ray.cpp
@ -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;
|
||||
|
36
geom/ray.hpp
36
geom/ray.hpp
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
36
io.cpp
@ -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
10
io.hpp
@ -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 *);
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -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)
|
||||
{ ; }
|
||||
|
||||
|
@ -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;
|
||||
|
219
iterator.hpp
219
iterator.hpp
@ -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
84
job/queue.cpp
Normal 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
154
job/queue.hpp
Normal 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
|
@ -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,
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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
94
json2/event.cpp
Normal 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
55
json2/event.hpp
Normal 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
|
@ -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
47
json2/fwd.hpp
Normal 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
332
json2/personality/base.cpp
Normal 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)
|
90
json2/personality/base.hpp
Normal file
90
json2/personality/base.hpp
Normal 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
|
201
json2/personality/jsonish.cpp
Normal file
201
json2/personality/jsonish.cpp
Normal 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);
|
||||
}
|
101
json2/personality/jsonish.hpp
Normal file
101
json2/personality/jsonish.hpp
Normal 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
|
21
json2/personality/rfc7519.cpp
Normal file
21
json2/personality/rfc7519.cpp
Normal 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;
|
100
json2/personality/rfc7519.hpp
Normal file
100
json2/personality/rfc7519.hpp
Normal 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
1
json2/tree.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "./tree.hpp"
|
@ -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
|
2
log.hpp
2
log.hpp
@ -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;
|
||||
|
||||
|
97
maths.hpp
97
maths.hpp
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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>&
|
||||
|
92
matrix.hpp
92
matrix.hpp
@ -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};
|
||||
|
84
matrix.ipp
84
matrix.ipp
@ -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> \
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 ());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
86
parse.cpp
Normal 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
53
parse.hpp
Normal 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
|
21
point.hpp
21
point.hpp
@ -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;
|
||||
};
|
||||
|
||||
|
44
pointer.hpp
44
pointer.hpp
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
455
preprocessor.hpp
455
preprocessor.hpp
@ -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
202
preprocessor.py
Executable 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")
|
92
random.hpp
92
random.hpp
@ -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 ())];
|
||||
}
|
||||
};
|
||||
|
||||
|
18
range.cpp
18
range.cpp
@ -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>;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
124
region.cpp
124
region.cpp
@ -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});
|
||||
}
|
||||
|
||||
|
||||
|
160
region.hpp
160
region.hpp
@ -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>;
|
||||
|
||||
|
10
signal.hpp
10
signal.hpp
@ -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&);
|
||||
|
||||
|
18
signal.ipp
18
signal.ipp
@ -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)...
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
42
string.hpp
42
string.hpp
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
6
tap.hpp
6
tap.hpp
@ -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);
|
||||
|
@ -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)
|
||||
);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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
229
test/crypto/salsa.cpp
Normal 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
31
test/endian.cpp
Normal 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
Loading…
Reference in New Issue
Block a user