build: migrate from ipp files to pure hpp files

ipp files weren't a great way of keeping things clean, and IDEs have a
little trouble dealing with the split configuration. this simplifies
debugging a great deal.
This commit is contained in:
Danny Robson 2018-02-28 11:49:13 +11:00
parent 3b3f9cd3d3
commit 0e3fa05f05
45 changed files with 950 additions and 1994 deletions

View File

@ -75,7 +75,6 @@ list (
APPEND UTIL_FILES APPEND UTIL_FILES
posix/dir.cpp posix/dir.cpp
posix/dir.hpp posix/dir.hpp
posix/dir.ipp
posix/except.cpp posix/except.cpp
posix/except.hpp posix/except.hpp
posix/fd.cpp posix/fd.cpp
@ -97,7 +96,6 @@ if (NOT WINDOWS)
debug_posix.cpp debug_posix.cpp
io_posix.cpp io_posix.cpp
io_posix.hpp io_posix.hpp
io_posix.ipp
library_posix.hpp library_posix.hpp
library_posix.cpp library_posix.cpp
posix/fwd.hpp posix/fwd.hpp
@ -116,7 +114,6 @@ if (WINDOWS)
exe_win32.cpp exe_win32.cpp
io_win32.cpp io_win32.cpp
io_win32.hpp io_win32.hpp
io_win32.ipp
library_win32.hpp library_win32.hpp
library_win32.cpp library_win32.cpp
time_win32.cpp time_win32.cpp
@ -138,14 +135,11 @@ list (
adapter.cpp adapter.cpp
algo/sort.cpp algo/sort.cpp
algo/sort.hpp algo/sort.hpp
algo/sort.ipp
alloc/fwd.hpp alloc/fwd.hpp
alloc/allocator.cpp alloc/allocator.cpp
alloc/allocator.hpp alloc/allocator.hpp
alloc/allocator.ipp
alloc/arena.cpp alloc/arena.cpp
alloc/arena.hpp alloc/arena.hpp
alloc/arena.ipp
alloc/raw/affix.cpp alloc/raw/affix.cpp
alloc/raw/affix.hpp alloc/raw/affix.hpp
alloc/raw/aligned.hpp alloc/raw/aligned.hpp
@ -173,10 +167,8 @@ list (
cast.hpp cast.hpp
cmdopt.cpp cmdopt.cpp
cmdopt.hpp cmdopt.hpp
cmdopt.ipp
colour.cpp colour.cpp
colour.hpp colour.hpp
colour.ipp
coord/fwd.hpp coord/fwd.hpp
coord/base.hpp coord/base.hpp
coord.hpp coord.hpp
@ -187,7 +179,6 @@ list (
coord/traits.hpp coord/traits.hpp
debug.cpp debug.cpp
debug.hpp debug.hpp
debug.ipp
encode/base.cpp encode/base.cpp
encode/base.hpp encode/base.hpp
endian.cpp endian.cpp
@ -195,7 +186,6 @@ list (
exe.hpp exe.hpp
extent.cpp extent.cpp
extent.hpp extent.hpp
extent.ipp
fixed.cpp fixed.cpp
fixed.hpp fixed.hpp
float.cpp float.cpp
@ -211,7 +201,6 @@ list (
geom/cylinder.hpp geom/cylinder.hpp
geom/ellipse.cpp geom/ellipse.cpp
geom/ellipse.hpp geom/ellipse.hpp
geom/ellipse.ipp
geom/iostream.cpp geom/iostream.cpp
geom/iostream.hpp geom/iostream.hpp
geom/ops.hpp geom/ops.hpp
@ -258,7 +247,6 @@ list (
introspection.hpp introspection.hpp
io.cpp io.cpp
io.hpp io.hpp
io.ipp
iterator.hpp iterator.hpp
job/queue.cpp job/queue.cpp
job/queue.hpp job/queue.hpp
@ -286,7 +274,6 @@ list (
library.hpp library.hpp
log.cpp log.cpp
log.hpp log.hpp
log.ipp
maths.cpp maths.cpp
maths.hpp maths.hpp
matrix.cpp matrix.cpp
@ -304,18 +291,14 @@ list (
platform.hpp platform.hpp
point.cpp point.cpp
point.hpp point.hpp
point.ipp
pointer.hpp pointer.hpp
polynomial.cpp polynomial.cpp
polynomial.hpp polynomial.hpp
polynomial.ipp
pool.cpp pool.cpp
pool.hpp pool.hpp
pool.ipp
preprocessor.hpp preprocessor.hpp
quaternion.cpp quaternion.cpp
quaternion.hpp quaternion.hpp
quaternion.ipp
raii.hpp raii.hpp
rand/lcg.cpp rand/lcg.cpp
rand/lcg.hpp rand/lcg.hpp
@ -327,20 +310,16 @@ list (
random.hpp random.hpp
range.cpp range.cpp
range.hpp range.hpp
range.ipp
rational.cpp rational.cpp
rational.hpp rational.hpp
rational.ipp
region.cpp region.cpp
region.hpp region.hpp
region.ipp
roots/bisection.hpp roots/bisection.hpp
sarray.cpp sarray.cpp
sarray.hpp sarray.hpp
si.cpp si.cpp
signal.cpp signal.cpp
signal.hpp signal.hpp
signal.ipp
si.hpp si.hpp
stats.cpp stats.cpp
stats.hpp stats.hpp
@ -378,7 +357,6 @@ list (
variadic.hpp variadic.hpp
vector.cpp vector.cpp
vector.hpp vector.hpp
vector.ipp
version.cpp version.cpp
version.hpp version.hpp
view.cpp view.cpp

View File

@ -18,7 +18,39 @@
#ifndef CRUFT_UTIL_ALGO_SORT_HPP #ifndef CRUFT_UTIL_ALGO_SORT_HPP
#define CRUFT_UTIL_ALGO_SORT_HPP #define CRUFT_UTIL_ALGO_SORT_HPP
#include "../debug.hpp"
#include <iterator>
#include <algorithm>
#include <numeric>
#include <vector>
namespace cruft::util::sort { namespace cruft::util::sort {
namespace detail {
template <typename IndexA, typename IndexB, typename RandomIt>
void
index_swap (IndexA a, IndexB b, RandomIt value)
{
static_assert(
std::is_base_of<
std::random_access_iterator_tag,
typename std::iterator_traits<RandomIt>::iterator_category
>::value
);
std::swap (value[a], value[b]);
}
template <typename IndexA, typename IndexB, typename RandomIt, typename ...Tail>
void
index_swap (IndexA a, IndexB b, RandomIt value, Tail ...tail)
{
index_swap (a, b, value);
index_swap (a, b, tail...);
};
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// rearrange the values in the arrays specified by the iterators value and // rearrange the values in the arrays specified by the iterators value and
// ...tail by moving values to the positions described by the mapping of // ...tail by moving values to the positions described by the mapping of
@ -31,7 +63,38 @@ namespace cruft::util::sort {
// the operation. // the operation.
template <typename IndexIt, typename ValueIt, typename ...OtherIt> template <typename IndexIt, typename ValueIt, typename ...OtherIt>
void void
reorder (IndexIt idx_first, IndexIt idx_last, ValueIt value, OtherIt ...tail); reorder (IndexIt idx_first, IndexIt idx_last, ValueIt value, OtherIt ...tail)
{
static_assert (
std::is_base_of<
std::random_access_iterator_tag,
typename std::iterator_traits<IndexIt>::iterator_category
>::value
);
static_assert (
std::is_base_of<
std::random_access_iterator_tag,
typename std::iterator_traits<ValueIt>::iterator_category
>::value
);
// Bail early on zero size arrays, partly so we can simplify some
// debugging checks
auto size = std::distance (idx_first, idx_last);
if (!size)
return;
CHECK_LT (*std::max_element (idx_first, idx_last), size);
for (decltype(size) i = 0; i < size - 1; ++i) {
while (i != (decltype(size))idx_first[i]) {
auto j = idx_first[i];
detail::index_swap (i, j, value, tail..., idx_first);
}
}
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// sort an array specified by the iterators key_first:key_last using a // sort an array specified by the iterators key_first:key_last using a
@ -41,9 +104,54 @@ namespace cruft::util::sort {
// sorting is performed in-place and will invariably allocate memory. // sorting is performed in-place and will invariably allocate memory.
template <typename RandomIt, class Comparator, class ...Args> template <typename RandomIt, class Comparator, class ...Args>
void void
soa (RandomIt key_first, RandomIt key_last, Comparator comp, Args ...values); soa (RandomIt key_first, RandomIt key_last, Comparator comp, Args ...values)
{
static_assert (
std::is_base_of<
std::random_access_iterator_tag,
typename std::iterator_traits<RandomIt>::iterator_category
>::value
);
// bail early on guaranteed sorted or degenerate cases. we can make some
// assumptions about minimum array sizes and non-wrapping indices later on
// this way.
if (std::distance (key_first, key_last) <= 1)
return;
// generate a list of indices into the key array and sort them so we have,
// in effect, a sorted list of pointers.
auto size = std::distance (key_first, key_last);
std::vector<decltype(size)> indices (size);
std::iota (std::begin (indices), std::end (indices), 0);
std::sort (std::begin (indices),
std::end (indices),
[&] (const auto &cruft_util_sort_soa_a, const auto &cruft_util_sort_soa_b)
{
// GCC: we use the ridiculous parameter names to avoid a name aliasing
// bug/warning under gcc 6.3.0; if the client passes a comparator
// lambda that uses the same parameter names then a warning will be
// generated. given 'a' and 'b' aren't unlikely names we try to avoid
// them here.
return comp (
key_first[cruft_util_sort_soa_a],
key_first[cruft_util_sort_soa_b]
);
});
// convert from a sorted list of pointers to a mapping of pointers to
// desired final offsets. this is done so we can palm it off to the
// reorder function.
// TODO: avoid the need for this inverse array.
decltype (indices) dest (indices.size ());
for (decltype(size) i = 0; i < (decltype(size))dest.size (); ++i) {
dest[indices[i]] = i;
} }
#include "sort.ipp" // reorder all the arrays using the mapping we have discovered.
reorder (std::begin (dest), std::end (dest), key_first, values...);
}
}
#endif #endif

View File

@ -1,155 +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:
* 2017, Danny Robson <danny@nerdcruft.net>
*/
#ifdef CRUFT_UTIL_ALGO_SORT_IPP
#error
#endif
#define CRUFT_UTIL_ALGO_SORT_IPP
#include <algorithm>
#include <array>
#include <iterator>
#include <numeric>
#include <vector>
#include <iterator>
#include <type_traits>
#include "../debug.hpp"
#include "../tuple.hpp"
///////////////////////////////////////////////////////////////////////////////
namespace cruft::util::sort::detail {
template <typename IndexA, typename IndexB, typename RandomIt>
void
index_swap (IndexA a, IndexB b, RandomIt value)
{
static_assert(
std::is_base_of<
std::random_access_iterator_tag,
typename std::iterator_traits<RandomIt>::iterator_category
>::value
);
std::swap (value[a], value[b]);
}
template <typename IndexA, typename IndexB, typename RandomIt, typename ...Tail>
void
index_swap (IndexA a, IndexB b, RandomIt value, Tail ...tail)
{
index_swap (a, b, value);
index_swap (a, b, tail...);
};
}
///////////////////////////////////////////////////////////////////////////////
template <typename IndexIt, typename ValueIt, typename ...OtherIt>
void
cruft::util::sort::reorder (IndexIt idx_first,
IndexIt idx_last,
ValueIt value,
OtherIt ...tail)
{
static_assert (
std::is_base_of<
std::random_access_iterator_tag,
typename std::iterator_traits<IndexIt>::iterator_category
>::value
);
static_assert (
std::is_base_of<
std::random_access_iterator_tag,
typename std::iterator_traits<ValueIt>::iterator_category
>::value
);
// Bail early on zero size arrays, partly so we can simplify some
// debugging checks
auto size = std::distance (idx_first, idx_last);
if (!size)
return;
CHECK_LT (*std::max_element (idx_first, idx_last), size);
for (decltype(size) i = 0; i < size - 1; ++i) {
while (i != (decltype(size))idx_first[i]) {
auto j = idx_first[i];
detail::index_swap (i, j, value, tail..., idx_first);
}
}
};
///////////////////////////////////////////////////////////////////////////////
template <typename RandomIt, class Comparator, class ...Args>
void
cruft::util::sort::soa (RandomIt key_first,
RandomIt key_last,
Comparator comp,
Args ...values)
{
static_assert (
std::is_base_of<
std::random_access_iterator_tag,
typename std::iterator_traits<RandomIt>::iterator_category
>::value
);
// bail early on guaranteed sorted or degenerate cases. we can make some
// assumptions about minimum array sizes and non-wrapping indices later on
// this way.
if (std::distance (key_first, key_last) <= 1)
return;
// generate a list of indices into the key array and sort them so we have,
// in effect, a sorted list of pointers.
auto size = std::distance (key_first, key_last);
std::vector<decltype(size)> indices (size);
std::iota (std::begin (indices), std::end (indices), 0);
std::sort (std::begin (indices),
std::end (indices),
[&] (const auto &cruft_util_sort_soa_a, const auto &cruft_util_sort_soa_b)
{
// GCC: we use the ridiculous parameter names to avoid a name aliasing
// bug/warning under gcc 6.3.0; if the client passes a comparator
// lambda that uses the same parameter names then a warning will be
// generated. given 'a' and 'b' aren't unlikely names we try to avoid
// them here.
return comp (
key_first[cruft_util_sort_soa_a],
key_first[cruft_util_sort_soa_b]
);
});
// convert from a sorted list of pointers to a mapping of pointers to
// desired final offsets. this is done so we can palm it off to the
// reorder function.
// TODO: avoid the need for this inverse array.
decltype (indices) dest (indices.size ());
for (decltype(size) i = 0; i < (decltype(size))dest.size (); ++i) {
dest[indices[i]] = i;
}
// reorder all the arrays using the mapping we have discovered.
reorder (std::begin (dest), std::end (dest), key_first, values...);
};

View File

@ -18,26 +18,38 @@
#define __UTIL_ALLOC_ALLOCATOR_HPP #define __UTIL_ALLOC_ALLOCATOR_HPP
#include <cstddef> #include <cstddef>
#include <utility>
// C++11 allocator concept conformant allocator adaptor, going from our // C++11 allocator concept conformant allocator adaptor, going from our
// allocator interface to that of the STL and friends. // allocator interface to that of the STL and friends.
namespace util::alloc { namespace util::alloc {
template <class B, class T> template <class BackingT, class ValueT>
class allocator { class allocator {
public: public:
typedef T value_type; typedef ValueT value_type;
template <typename ...Args> template <typename ...Args>
explicit allocator (Args&& ...args); explicit allocator (Args&& ...args):
m_backing (std::forward (args)...)
{ ; }
ValueT* allocate (size_t count)
{
return m_backing.template allocate<ValueT> (count);
}
void
deallocate (ValueT *t, size_t count)
{
return m_backing.template deallocate (t, count);
}
T* allocate (size_t count);
void deallocate (T*, size_t count);
private: private:
B &m_backing; BackingT &m_backing;
}; };
} }
#include "allocator.ipp"
#endif #endif

View File

@ -1,49 +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>
*/
#ifdef __UTIL_ALLOC_ALLOCATOR_IPP
#error
#endif
#define __UTIL_ALLOC_ALLOCATOR_IPP
#include <utility>
///////////////////////////////////////////////////////////////////////////////
template <class B, class T>
template <typename ...Args>
util::alloc::allocator<B,T>::allocator (Args&& ...args):
m_backing (std::forward (args)...)
{ ; }
///////////////////////////////////////////////////////////////////////////////
template <class B, class T>
T*
util::alloc::allocator<B,T>::allocate (std::size_t count)
{
return m_backing.template allocate<T> (count);
}
//-----------------------------------------------------------------------------
template <class B, class T>
void
util::alloc::allocator<B,T>::deallocate (T *t, std::size_t count)
{
return m_backing.template deallocate (t, count);
}

View File

@ -28,17 +28,38 @@ namespace util::alloc {
template <class T> template <class T>
class arena { class arena {
public: public:
explicit arena (T &store); explicit arena (T &store):
m_store (store)
{ ; }
//--------------------------------------------------------------------- //---------------------------------------------------------------------
template <typename U, typename ...Args> template <typename U, typename ...Args>
U* U*
acquire (Args&&...); acquire (Args&&... args)
{
U *data = reinterpret_cast<U*> (
m_store.allocate (sizeof (U), alignof (U))
);
try {
new (data) U (std::forward<Args> (args)...);
} catch (...) {
m_store.deallocate (data, sizeof (U));
throw;
}
return data;
}
//--------------------------------------------------------------------- //---------------------------------------------------------------------
template <typename U> template <typename U>
void void
release (U*); release (U *u)
{
u->~U ();
m_store.deallocate (reinterpret_cast<void*> (u), sizeof (U));
}
//--------------------------------------------------------------------- //---------------------------------------------------------------------
template <typename U> template <typename U>
@ -68,6 +89,4 @@ namespace util::alloc {
}; };
} }
#include "arena.ipp"
#endif #endif

View File

@ -1,62 +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>
*/
#ifdef __UTIL_ALLOC_ARENA_IPP
#error
#endif
#define __UTIL_ALLOC_ARENA_IPP
///////////////////////////////////////////////////////////////////////////////
template <class T>
util::alloc::arena<T>::arena (T &store):
m_store (store)
{ ; }
///////////////////////////////////////////////////////////////////////////////
template <class T>
template <typename U, typename ...Args>
U*
util::alloc::arena<T>::acquire (Args&& ...args)
{
U *data = reinterpret_cast<U*> (
m_store.allocate (sizeof (U), alignof (U))
);
try {
new (data) U (std::forward<Args> (args)...);
} catch (...) {
m_store.deallocate (data, sizeof (U));
throw;
}
return data;
}
//-----------------------------------------------------------------------------
template <class T>
template <typename U>
void
util::alloc::arena<T>::release (U *u)
{
u->~U ();
m_store.deallocate (reinterpret_cast<void*> (u), sizeof (U));
}

View File

@ -15,19 +15,72 @@
*/ */
#ifndef __UTIL_CMDLINE_HPP #ifndef CRUFT_UTIL_CMDLINE_HPP
#define __UTIL_CMDLINE_HPP #define CRUFT_UTIL_CMDLINE_HPP
#include "introspection.hpp"
#include "iterator.hpp"
#include <exception>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <exception>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
#include <sstream>
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
namespace util::cmdopt { namespace util::cmdopt {
///////////////////////////////////////////////////////////////////////////
class error : public std::exception { };
//-------------------------------------------------------------------------
class invalid_key : public error {
public:
explicit invalid_key (std::string _key);
const char* what (void) const noexcept override;
private:
const std::string m_key;
};
//-------------------------------------------------------------------------
class invalid_value : public error {
public:
explicit invalid_value (std::string _value);
const char* what (void) const noexcept override;
private:
const std::string m_value;
};
//-------------------------------------------------------------------------
class invalid_null : public error {
public:
const char* what (void) const noexcept override;
};
//-------------------------------------------------------------------------
class invalid_required : public error {
public:
const char* what (void) const noexcept override;
};
//-------------------------------------------------------------------------
class unhandled_argument : public error {
public:
explicit unhandled_argument (int index);
const char* what (void) const noexcept override;
int index (void) const noexcept;
private:
const int m_index;
};
///////////////////////////////////////////////////////////////////////////
namespace option { namespace option {
class base { class base {
public: public:
@ -84,25 +137,125 @@ namespace util::cmdopt {
}; };
namespace detail {
template <typename T>
std::enable_if_t<!std::is_enum<T>::value, const std::string&>
value_example (void)
{
static const std::string EXAMPLE =
std::string {"<"} +
std::string {to_string<T> ()} +
std::string {">"};
return EXAMPLE;
}
template <typename T>
std::enable_if_t<std::is_enum<T>::value, const std::string&>
value_example (void)
{
static const std::string EXAMPLE = [] (void) {
std::ostringstream os;
std::copy (std::cbegin (enum_traits<T>::names),
std::cend (enum_traits<T>::names),
infix_iterator<const char*> (os, "|"));
return os.str ();
} ();
return EXAMPLE;
}
}
template <typename T> template <typename T>
class value : public base { class value : public base {
public: public:
explicit value (T&); explicit value (T &_data): m_data (_data) { }
explicit value (T&&) = delete; explicit value (T&&) = delete;
using base::execute; using base::execute;
void execute (const char *restrict) override;
const std::string& example (void) const override; void execute (const char *restrict str) override
{
try {
std::istringstream is (str);
is.exceptions (
std::istringstream::failbit
| std::istringstream::badbit
);
const T& data (void) const&; is >> m_data;
T& data (void) &; } catch (...) {
T& data (T) &; throw invalid_value (__func__);
}
seen (true);
}
const std::string& example (void) const override
{
return detail::value_example<T> ();
}
const T& data (void) const&
{
return m_data;
}
T& data (void) &
{
return m_data;
}
T& data (T _data) &
{
return m_data = _data;
}
private: private:
T& m_data; T& m_data;
}; };
template <>
inline void
value<bool>::execute (const char *restrict str)
{
static const std::string TRUE_STRING[] = {
"true",
"yes",
"y",
"1"
};
if (std::any_of (std::begin (TRUE_STRING),
std::end (TRUE_STRING),
[str] (auto i) { return i == str; }))
{
m_data = true;
return;
}
static const std::string FALSE_STRING[] = {
"false",
"no",
"n",
"0"
};
if (std::any_of (std::begin (FALSE_STRING),
std::end (FALSE_STRING),
[str] (auto i) { return i == str; }))
{
m_data = false;
return;
}
base::execute (str);
seen (true);
}
template <typename T = unsigned> template <typename T = unsigned>
class count : public value<T> { class count : public value<T> {
@ -132,11 +285,29 @@ namespace util::cmdopt {
T& add (char shortname, T& add (char shortname,
std::string longname, std::string longname,
std::string description, std::string description,
Args&&...); Args&&... args)
{
auto handler = std::make_unique<T> (std::forward<Args> (args)...);
T& ref = *handler;
m_short.emplace_back (shortname, ref);
m_long .emplace_back (std::move (longname), ref);
m_options.emplace_back (std::move (description), std::move (handler));
return ref;
}
template <typename T, typename ...Args> template <typename T, typename ...Args>
T& T&
append (std::string description, Args&&...); append (std::string description, Args&&...args)
{
auto handler = std::make_unique<T> (std::forward<Args> (args)...);
auto &ref = *handler;
m_positional.push_back (ref);
m_options.emplace_back (std::move (description), std::move (handler));
return ref;
}
int scan (int argc, const char *const *argv); int scan (int argc, const char *const *argv);
@ -160,56 +331,6 @@ namespace util::cmdopt {
> >
> m_options; > m_options;
}; };
///////////////////////////////////////////////////////////////////////////
class error : public std::exception { };
//-------------------------------------------------------------------------
class invalid_key : public error {
public:
explicit invalid_key (std::string _key);
const char* what (void) const noexcept override;
private:
const std::string m_key;
};
//-------------------------------------------------------------------------
class invalid_value : public error {
public:
explicit invalid_value (std::string _value);
const char* what (void) const noexcept override;
private:
const std::string m_value;
};
//-------------------------------------------------------------------------
class invalid_null : public error {
public:
const char* what (void) const noexcept override;
};
//-------------------------------------------------------------------------
class invalid_required : public error {
public:
const char* what (void) const noexcept override;
};
//-------------------------------------------------------------------------
class unhandled_argument : public error {
public:
explicit unhandled_argument (int index);
const char* what (void) const noexcept override;
int index (void) const noexcept;
private:
const int m_index;
};
} }
#include "cmdopt.ipp"
#endif #endif

View File

@ -1,198 +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 2013-2016 Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_CMDLINE_IPP
#error
#endif
#define __UTIL_CMDLINE_IPP
#include <algorithm>
#include <iterator>
#include <sstream>
#include "introspection.hpp"
#include "iterator.hpp"
namespace util::cmdopt {
///////////////////////////////////////////////////////////////////////////
template <typename T>
option::value<T>::value (T &_data):
m_data (_data)
{ ; }
//-------------------------------------------------------------------------
template <typename T>
inline void
option::value<T>::execute (const char *restrict str)
{
try {
std::istringstream is (str);
is.exceptions (
std::istringstream::failbit
| std::istringstream::badbit
);
is >> m_data;
} catch (...) {
throw invalid_value (__func__);
}
seen (true);
}
//-------------------------------------------------------------------------
namespace option {
template <>
inline void
value<bool>::execute (const char *restrict str)
{
static const std::string TRUE_STRING[] = {
"true",
"yes",
"y",
"1"
};
if (std::any_of (std::begin (TRUE_STRING),
std::end (TRUE_STRING),
[str] (auto i) { return i == str; }))
{
m_data = true;
return;
}
static const std::string FALSE_STRING[] = {
"false",
"no",
"n",
"0"
};
if (std::any_of (std::begin (FALSE_STRING),
std::end (FALSE_STRING),
[str] (auto i) { return i == str; }))
{
m_data = false;
return;
}
base::execute (str);
seen (true);
}
}
//-------------------------------------------------------------------------
namespace detail {
template <typename T>
std::enable_if_t<!std::is_enum<T>::value, const std::string&>
value_example (void)
{
static const std::string EXAMPLE =
std::string {"<"} +
std::string {to_string<T> ()} +
std::string {">"};
return EXAMPLE;
}
template <typename T>
std::enable_if_t<std::is_enum<T>::value, const std::string&>
value_example (void)
{
static const std::string EXAMPLE = [] (void) {
std::ostringstream os;
std::copy (std::cbegin (enum_traits<T>::names),
std::cend (enum_traits<T>::names),
infix_iterator<const char*> (os, "|"));
return os.str ();
} ();
return EXAMPLE;
}
}
//-------------------------------------------------------------------------
template <typename T>
const std::string&
option::value<T>::example (void) const
{
return detail::value_example<T> ();
}
//-----------------------------------------------------------------------------
template <typename T>
const T&
option::value<T>::data (void) const&
{
return m_data;
}
//-----------------------------------------------------------------------------
template <typename T>
T&
option::value<T>::data (void) &
{
return m_data;
}
//-----------------------------------------------------------------------------
template <typename T>
T&
option::value<T>::data (T _data) &
{
return m_data = _data;
}
///////////////////////////////////////////////////////////////////////////
template <typename T, typename ...Args>
T&
parser::add (char shortname,
std::string longname,
std::string description,
Args&&... args)
{
auto handler = std::make_unique<T> (std::forward<Args> (args)...);
T& ref = *handler;
m_short.emplace_back (shortname, ref);
m_long .emplace_back (std::move (longname), ref);
m_options.emplace_back (std::move (description), std::move (handler));
return ref;
}
//-------------------------------------------------------------------------
template <typename T, typename ...Args>
T&
parser::append (std::string description,
Args &&...args)
{
auto handler = std::make_unique<T> (std::forward<Args> (args)...);
auto &ref = *handler;
m_positional.push_back (ref);
m_options.emplace_back (std::move (description), std::move (handler));
return ref;
}
}

View File

@ -115,6 +115,4 @@ namespace util {
constexpr auto is_colour_v = is_colour<T>::value; constexpr auto is_colour_v = is_colour<T>::value;
} }
#include "colour.ipp"
#endif #endif

View File

@ -1,21 +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 2010-2015 Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_COLOUR_IPP
#error
#endif
#define __UTIL_COLOUR_IPP

View File

@ -371,25 +371,101 @@ namespace util::debug {
} }
void breakpoint (void);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
constexpr void panic [[noreturn]] (const char*); #include "log.hpp"
#include "backtrace.hpp"
namespace util::debug::detail {
void panic [[noreturn]] (const char *msg);
template <typename ...Args, size_t N> template <typename ...Args, size_t N>
constexpr void panic [[noreturn]] (const char (&fmt)[N], const Args& ...args)
void panic [[noreturn]] (const char (&fmt)[N], const Args&...); {
LOG_EMERGENCY (fmt, args...);
LOG_EMERGENCY ("%!", ::debug::backtrace ());
breakpoint ();
abort ();
}
void not_implemented [[noreturn]] (const char *msg);
void unreachable [[noreturn]] (const char *msg);
}
constexpr void
panic [[noreturn]] (const char *msg)
{
! msg
? panic (msg)
: util::debug::detail::panic (msg);
}
template <typename ...Args, size_t N>
constexpr void
panic [[noreturn]] (const char (&fmt)[N], const Args&... args)
{
util::debug::detail::panic (fmt, args...);
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
constexpr void not_implemented [[noreturn]] (void); // not_implemented/unreachable/panic must be callable from constexpr contexts.
constexpr void not_implemented [[noreturn]] (const char *msg); // but they rely on functions that aren't constexpr to perform the controlled
// abort.
//
// we can work around this in the same way assert does by using a conditional
// that hides an extern function that actually does the work. as we can't
// utilise external state this has to be the message variable which will
// assume isn't ever null.
//
// to avoid warnings about a return from a noreturn function we recurse into
// ourself in the alternate case. this branch shouldn't ever be taken, but if
// it is we were planning on crashing anyway...
///////////////////////////////////////////////////////////////////////////////
constexpr void
not_implemented [[noreturn]] (const char *msg)
{
! msg
? not_implemented (msg)
: util::debug::detail::not_implemented (msg);
}
constexpr void
not_implemented [[noreturn]] (void)
{
not_implemented ("operation not implemented");
}
constexpr void unimplemented [[noreturn]] (void) { not_implemented (); } constexpr void unimplemented [[noreturn]] (void) { not_implemented (); }
constexpr void unimplemented [[noreturn]] (const char *msg) { not_implemented (msg); } constexpr void unimplemented [[noreturn]] (const char *msg) { not_implemented (msg); }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
constexpr void unreachable [[noreturn]] (void); constexpr void
constexpr void unreachable [[noreturn]] (const char*); unreachable [[noreturn]] (const char *msg)
{
! msg
? unreachable (msg)
: util::debug::detail::unreachable (msg);
}
constexpr void
unreachable [[noreturn]] (void)
{
unreachable ("unreachable code executed");
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -410,8 +486,6 @@ void warn (const char *);
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
void breakpoint (void);
void await_debugger (void); void await_debugger (void);
void prepare_debugger (void); void prepare_debugger (void);
@ -514,11 +588,6 @@ namespace util::debug {
} }
#include "debug.ipp"
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// XXX: maths needs to be included so that CHECK_EQ/NEQ can call almost_equal, // XXX: maths needs to be included so that CHECK_EQ/NEQ can call almost_equal,
// but maths.hpp might be using CHECK_ macros so we must include maths.hpp // but maths.hpp might be using CHECK_ macros so we must include maths.hpp

108
debug.ipp
View File

@ -1,108 +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-2018, Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_DEBUG_IPP
#error
#endif
#define __UTIL_DEBUG_IPP
#include "backtrace.hpp"
#include "format.hpp"
#include <limits>
#include <iostream>
///////////////////////////////////////////////////////////////////////////////
namespace util::debug::detail {
void panic [[noreturn]] (const char *msg);
template <typename ...Args, size_t N>
void panic [[noreturn]] (const char (&fmt)[N], const Args& ...args)
{
std::cerr << ::util::format::printf (fmt, args...) << ::debug::backtrace () << std::endl;
breakpoint ();
abort ();
}
void not_implemented [[noreturn]] (const char *msg);
void unreachable [[noreturn]] (const char *msg);
}
// not_implemented/unreachable/panic must be callable from constexpr contexts.
// but they rely on functions that aren't constexpr to perform the controlled
// abort.
//
// we can work around this in the same way assert does by using a conditional
// that hides an extern function that actually does the work. as we can't
// utilise external state this has to be the message variable which will
// assume isn't ever null.
//
// to avoid warnings about a return from a noreturn function we recurse into
// ourself in the alternate case. this branch shouldn't ever be taken, but if
// it is we were planning on crashing anyway...
///////////////////////////////////////////////////////////////////////////////
constexpr void not_implemented [[noreturn]] (void)
{
not_implemented ("operation not implemented");
}
//-----------------------------------------------------------------------------
constexpr void not_implemented [[noreturn]] (const char *msg)
{
! msg
? not_implemented (msg)
: util::debug::detail::not_implemented (msg);
}
///////////////////////////////////////////////////////////////////////////////
constexpr void unreachable [[noreturn]] (void)
{
unreachable ("unreachable code executed");
}
//-----------------------------------------------------------------------------
constexpr void unreachable [[noreturn]] (const char *msg)
{
! msg
? unreachable (msg)
: util::debug::detail::unreachable (msg);
}
///////////////////////////////////////////////////////////////////////////////
constexpr void panic [[noreturn]] (const char *msg)
{
! msg
? panic (msg)
: util::debug::detail::panic (msg);
}
//-----------------------------------------------------------------------------
template <typename ...Args, size_t N>
constexpr
void
panic [[noreturn]] (const char (&fmt)[N], const Args& ...args)
{
util::debug::detail::panic (fmt, args...);
}

View File

@ -14,8 +14,8 @@
* Copyright 2010-2017 Danny Robson <danny@nerdcruft.net> * Copyright 2010-2017 Danny Robson <danny@nerdcruft.net>
*/ */
#ifndef __UTIL_EXTENT_HPP #ifndef CRUFT_UTIL_EXTENT_HPP
#define __UTIL_EXTENT_HPP #define CRUFT_UTIL_EXTENT_HPP
#include "coord/fwd.hpp" #include "coord/fwd.hpp"
#include "coord/base.hpp" #include "coord/base.hpp"
@ -36,12 +36,34 @@ namespace util {
extent () = default; extent () = default;
explicit extent (::util::vector<S,T>); explicit extent (::util::vector<S,T>);
constexpr T area (void) const; constexpr T
constexpr T diameter (void) const; area (void) const
{
return std::accumulate (std::begin (this->data),
std::end (this->data),
T {1},
std::multiplies<T> ());
}
constexpr T
diameter (void) const
{
return static_cast<T> (
std::sqrt (
std::accumulate (std::begin (this->data),
std::end (this->data),
T {0},
[] (auto a, auto b) { return a + b * b; })
)
);
}
template <typename U = float> template <typename U = float>
constexpr constexpr
U aspect (void) const; U aspect (void) const
{
return static_cast<U> (this->w) / this->h;
}
/// tests whether a point would lie within: /// tests whether a point would lie within:
/// region { origin, *this }, inclusive of borders. /// region { origin, *this }, inclusive of borders.
@ -70,8 +92,20 @@ namespace util {
bool empty (void) const; bool empty (void) const;
static constexpr ::util::extent<S,T> max (void); static constexpr
static constexpr ::util::extent<S,T> min (void); ::util::extent<S,T> max (void)
{
return extent<S,T> {
std::numeric_limits<T>::max ()
};
}
static constexpr
::util::extent<S,T> min (void)
{
return extent<S,T> { 0 };
}
}; };
template <size_t S, typename T> template <size_t S, typename T>
@ -147,6 +181,4 @@ namespace util {
} }
#include "extent.ipp"
#endif #endif

View File

@ -1,88 +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-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_EXTENT_IPP
#error
#endif
#define __UTIL_EXTENT_IPP
#include <algorithm>
#include <limits>
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
constexpr
T
util::extent<S,T>::diameter (void) const
{
return static_cast<T> (
std::sqrt (
std::accumulate (std::begin (this->data),
std::end (this->data),
T {0},
[] (auto a, auto b) { return a + b * b; })
)
);
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
constexpr
T
util::extent<S,T>::area (void) const
{
return std::accumulate (std::begin (this->data),
std::end (this->data),
T {1},
std::multiplies<T> ());
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
template <typename U>
constexpr
U
util::extent<S,T>::aspect (void) const
{
return static_cast<U> (this->w) / this->h;
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
constexpr
util::extent<S,T>
util::extent<S,T>::max (void)
{
return extent<S,T> {
std::numeric_limits<T>::max ()
};
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
constexpr
util::extent<S,T>
util::extent<S,T>::min (void)
{
return extent<S,T> { 0 };
}

View File

@ -24,13 +24,37 @@
namespace util::geom { namespace util::geom {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
template <size_t S, typename T> template <size_t S, typename ValueT>
struct ellipse { struct ellipse {
util::point<S,T> origin; util::point<S,ValueT> origin;
util::vector<S,T> radius; util::vector<S,ValueT> radius;
}; };
} }
#include "ellipse.ipp"
///////////////////////////////////////////////////////////////////////////////
#include "sample.hpp"
#include <cmath>
#include <random>
namespace util::geom {
template <typename T, template <size_t,typename> class K, typename G>
struct sampler<2,T,K,G>
{
static util::point<2,T> fn (K<2,T> k, G &g)
{
std::uniform_real_distribution<T> dist;
float phi = dist (g) * 2 * PI<T>;
float rho = std::sqrt (dist (g));
return util::point<2,T> {
std::cos (phi),
std::sin (phi)
} * rho * k.radius + k.origin.template as<util::vector> ();
}
};
}
#endif #endif

View File

@ -1,46 +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_ELLIPSE_IPP)
#error
#endif
#define __UTIL_GEOM_ELLIPSE_IPP
#include "sample.hpp"
#include <cmath>
#include <random>
///////////////////////////////////////////////////////////////////////////////
namespace util::geom {
template <typename T, template <size_t,typename> class K, typename G>
struct sampler<2,T,K,G>
{
static util::point<2,T> fn (K<2,T> k, G &g)
{
std::uniform_real_distribution<T> dist;
float phi = dist (g) * 2 * PI<T>;
float rho = std::sqrt (dist (g));
return util::point<2,T> {
std::cos (phi),
std::sin (phi)
} * rho * k.radius + k.origin.template as<util::vector> ();
}
};
}

28
io.hpp
View File

@ -94,23 +94,27 @@ namespace util {
}; };
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
template <typename T> // a wrapper type that implicitly indents a single value when passed to an
// ostream operator.
template <typename ValueT>
struct indented { struct indented {
explicit indented (const T &_data); explicit indented (const ValueT &_data):
const T &data; data (_data)
{ ; }
const ValueT &data;
}; };
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
template <typename T> template <typename ValueT>
indented<T>
make_indented (const T &_data);
//-------------------------------------------------------------------------
template <typename T>
std::ostream& std::ostream&
operator<< (std::ostream &os, const util::indented<T> &v); operator<< (std::ostream &os, const util::indented<ValueT> &value)
{
util::indenter scoped_indent (os);
return os << value.data;
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -148,6 +152,4 @@ namespace util {
#include "io_posix.hpp" #include "io_posix.hpp"
#endif #endif
#include "io.ipp"
#endif #endif

49
io.ipp
View File

@ -1,49 +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:
* 2014-2015, Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_IO_IPP
#error "multiple inclusions"
#else
#define __UTIL__IO_IPP
#endif
namespace util {
//-------------------------------------------------------------------------
template <typename T>
indented<T>::indented (const T &_data):
data (_data)
{ ; }
//-------------------------------------------------------------------------
template <typename T>
indented<T>
make_indented (const T &_data) {
return indented<T> (_data);
}
//-------------------------------------------------------------------------
template <typename T>
std::ostream&
operator<< (std::ostream &os, const util::indented<T> &&v) {
util::indenter raii (os);
os << v.data;
return os;
}
}

View File

@ -81,6 +81,4 @@ namespace util {
typedef detail::posix::mapped_file mapped_file; typedef detail::posix::mapped_file mapped_file;
} }
#include "io_posix.ipp"
#endif #endif

View File

@ -1,23 +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 2016 Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_IO_POSIX_IPP
#error
#endif
#define __UTIL_IO_POSIX_IPP
#include "pointer.hpp"

View File

@ -84,11 +84,23 @@ namespace util {
template <typename T> template <typename T>
util::view<std::add_const_t<T>*> util::view<std::add_const_t<T>*>
as_view () const &; as_view () const &
{
return {
reinterpret_cast<const T*> (cbegin ()),
reinterpret_cast<const T*> (align (cend (), alignof (T)))
};
}
template <typename T> template <typename T>
util::view<T*> util::view<T*>
as_view () &; as_view () &
{
return {
reinterpret_cast<T *> (begin ()),
reinterpret_cast<T *> (align (end (), alignof(T)))
};
}
private: private:
::util::win32::handle m_file; ::util::win32::handle m_file;
@ -102,6 +114,4 @@ namespace util {
typedef detail::win32::mapped_file mapped_file; typedef detail::win32::mapped_file mapped_file;
} }
#include "io_win32.ipp"
#endif #endif

View File

@ -1,48 +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 2016 Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_IO_WIN32_IPP
#error
#endif
#define __UTIL_IO_WIN32_IPP
#include "pointer.hpp"
///////////////////////////////////////////////////////////////////////////////
template <typename T>
util::view<std::add_const_t<T>*>
util::detail::win32::mapped_file::as_view (void) const&
{
return {
reinterpret_cast<const T*> (cbegin ()),
reinterpret_cast<const T*> (align (cend (), alignof (T)))
};
}
//-----------------------------------------------------------------------------
template <typename T>
util::view<T*>
util::detail::win32::mapped_file::as_view (void) &
{
return {
reinterpret_cast<T *> (begin ()),
reinterpret_cast<T *> (align (end (), alignof(T)))
};
}

View File

@ -135,7 +135,5 @@ namespace util {
}; };
} }
#include "log.ipp"
#endif #endif

15
log.ipp
View File

@ -1,15 +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>
*/

View File

@ -14,12 +14,14 @@
* Copyright 2011-2016 Danny Robson <danny@nerdcruft.net> * Copyright 2011-2016 Danny Robson <danny@nerdcruft.net>
*/ */
#ifndef __UTIL_POINT_HPP #ifndef CRUFT_UTIL_POINT_HPP
#define __UTIL_POINT_HPP #define CRUFT_UTIL_POINT_HPP
#include "vector.hpp" #include "vector.hpp"
#include "coord.hpp" #include "coord.hpp"
#include "maths.hpp"
#include <algorithm>
#include <type_traits> #include <type_traits>
namespace util { namespace util {
@ -35,7 +37,29 @@ namespace util {
vector<S,T> to (point) const; vector<S,T> to (point) const;
vector<S,T> from (point) const; vector<S,T> from (point) const;
template <size_t D> point<D,T> homog (void) const; /// expand point to use homogenous coordinates of a higher dimension.
/// ie, fill with (0,..,0,1)
template <size_t D>
point<D,T>
homog (void) const
{
static_assert (D > S, "homog will not overwrite data");
point<D,T> out;
// Copy the existing data
auto c = std::copy (this->begin (),
this->end (),
out.begin ());
// Fill until the second last element with zeros
auto f = std::fill_n (c, D - S - 1, T{0});
// Last element should be one
*f = T{1};
return out;
}
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
static constexpr static constexpr
@ -54,7 +78,10 @@ namespace util {
//------------------------------------------------------------------- //-------------------------------------------------------------------
static constexpr static constexpr
point<S,T> origin (void); point<S,T> origin (void)
{
return point<S,T> {0};
}
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
@ -66,33 +93,75 @@ namespace util {
/// computes the exact euclidean distance between two points. /// computes the exact euclidean distance between two points.
template <size_t S, typename T, typename U> template <size_t S, typename T, typename U>
typename std::common_type<T,U>::type distance (point<S,T>, point<S,U>); typename std::common_type<T,U>::type
distance (point<S,T> a, point<S,U> b)
{
using type_t = typename std::common_type<T,U>::type;
static_assert (std::is_floating_point<type_t>::value,
"sqrt likely requires fractional types");
return std::sqrt (distance2 (a, b));
}
/// computes the squared euclidean distance between two points. /// computes the squared euclidean distance between two points.
/// ///
/// useful if you just need to compare distances because it avoids a sqrt /// useful if you just need to compare distances because it avoids a sqrt
/// operation. /// operation.
template <size_t S, typename T, typename U> template <size_t S, typename T, typename U>
constexpr typename std::common_type<T,U>::type distance2 (point<S,T>, point<S,U>); constexpr typename std::common_type<T,U>::type
distance2 (point<S,T> a, point<S,U> b)
{
return sum (pow2 (a - b));
}
/// computes the octile distance between two points. that is, the shortest /// computes the octile distance between two points. that is, the shortest
/// distance between `a' and `b' where travel is only allowed beween the 8 /// distance between `a' and `b' where travel is only allowed beween the 8
/// grid neighbours and cost for diagonals is proportionally larger than /// grid neighbours and cost for diagonals is proportionally larger than
/// cardinal movement. see also: chebyshev. /// cardinal movement. see also: chebyshev.
template <typename T, typename U> template <typename T, typename U>
typename std::common_type<T,U>::type octile (point<2,T>, point<2,U>); typename std::common_type<T,U>::type
octile (point<2,T> a, point<2,U> b)
{
using type_t = typename std::common_type<T,U>::type;
static_assert (!std::is_integral<type_t>::value,
"octile requires more than integer precision");
const type_t D1 = 1;
const type_t D2 = std::sqrt (type_t {2});
auto diff = util::abs (a - b);
// distance for axis-aligned walks
auto axis = D1 * (diff.x + diff.y);
// the savings from diagonal walks
auto diag = (D2 - 2 * D1) * util::min (diff);
return axis + diag;
}
/// computes the manhattan distance between two points. that is, the /// computes the manhattan distance between two points. that is, the
/// distance where travel is only allowed along cardinal directions. /// distance where travel is only allowed along cardinal directions.
template <size_t S, typename T, typename U> template <size_t S, typename T, typename U>
constexpr typename std::common_type<T,U>::type manhattan (point<S,T>, point<S,U>); constexpr typename std::common_type<T,U>::type
manhattan (point<S,T> a, point<S,U> b)
{
return sum (abs (a - b));
}
/// computes the cheyvshev distance between two points. that is, the /// computes the cheyvshev distance between two points. that is, the
/// shortest distance between `a' and `b' where travel is only allowed /// shortest distance between `a' and `b' where travel is only allowed
/// between the 8 grid neighbours and cost for diagonals is the same as /// between the 8 grid neighbours and cost for diagonals is the same as
/// cardinal movement. see also: octile. /// cardinal movement. see also: octile.
template <size_t S, typename T, typename U> template <size_t S, typename T, typename U>
constexpr typename std::common_type<T,U>::type chebyshev (point<S,T>, point<S,U>); constexpr typename std::common_type<T,U>::type
chebyshev (point<S,T> a, point<S,U> b)
{
return util::max (abs (a - b));
}
// Convenience typedefs // Convenience typedefs
template <typename T> using point1 = point<1,T>; template <typename T> using point1 = point<1,T>;
@ -122,6 +191,4 @@ namespace util {
typedef point4<int> point4i; typedef point4<int> point4i;
} }
#include "point.ipp"
#endif // __UTIL_POINT_HPP #endif // __UTIL_POINT_HPP

120
point.ipp
View File

@ -1,120 +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 2014-2015 Danny Robson <danny@nerdcruft.net>
*/
#include "maths.hpp"
#include <algorithm>
///////////////////////////////////////////////////////////////////////////////
/// expand point to use homogenous coordinates of a higher dimension.
/// ie, fill with (0,..,0,1)
template <size_t S, typename T>
template <size_t D>
util::point<D,T>
util::point<S,T>::homog (void) const
{
static_assert (D > S, "homog will not overwrite data");
point<D,T> out;
// Copy the existing data
auto c = std::copy (this->begin (),
this->end (),
out.begin ());
// Fill until the second last element with zeros
auto f = std::fill_n (c, D - S - 1, T{0});
// Last element should be one
*f = T{1};
return out;
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
constexpr
util::point<S,T>
util::point<S,T>::origin (void)
{
return point<S,T> {0};
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T, typename U>
typename std::common_type<T,U>::type
util::distance (point<S,T> a, point<S,U> b)
{
using type_t = typename std::common_type<T,U>::type;
static_assert (std::is_floating_point<type_t>::value,
"sqrt likely requires fractional types");
return std::sqrt (distance2 (a, b));
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T, typename U>
constexpr typename std::common_type<T,U>::type
util::distance2 (point<S,T> a, point<S,U> b)
{
return sum (pow2 (a - b));
}
///////////////////////////////////////////////////////////////////////////////
template <typename T, typename U>
typename std::common_type<T,U>::type
util::octile (point2<T> a, point2<U> b)
{
using type_t = typename std::common_type<T,U>::type;
static_assert (!std::is_integral<type_t>::value,
"octile requires more than integer precision");
const type_t D1 = 1;
const type_t D2 = std::sqrt (type_t {2});
auto diff = util::abs (a - b);
// distance for axis-aligned walks
auto axis = D1 * (diff.x + diff.y);
// the savings from diagonal walks
auto diag = (D2 - 2 * D1) * util::min (diff);
return axis + diag;
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T, typename U>
constexpr typename std::common_type<T,U>::type
util::manhattan (point<S,T> a, point<S,U> b)
{
return sum (abs (a - b));
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T, typename U>
constexpr typename std::common_type<T,U>::type
util::chebyshev(point<S,T> a, point<S,U> b)
{
return util::max (abs (a - b));
}

View File

@ -14,8 +14,8 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net> * Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/ */
#ifndef __UTIL_POLYNOMIAL_HPP #ifndef CRUFT_UTIL_POLYNOMIAL_HPP
#define __UTIL_POLYNOMIAL_HPP #define CRUFT_UTIL_POLYNOMIAL_HPP
#include <array> #include <array>
#include <cstdlib> #include <cstdlib>
@ -30,9 +30,18 @@ namespace util::polynomial {
template <size_t S, typename T, typename U> template <size_t S, typename T, typename U>
T T
eval (std::array<T,S>, U x); eval (std::array<T,S> coeffs, U x)
{
U x_ = 1.f;
T sum {0.f};
for (size_t i = 0; i < S; ++i) {
sum += coeffs[S-i-1] * x_;
x_ *= x;
} }
#include "polynomial.ipp" return sum;
}
}
#endif #endif

View File

@ -1,39 +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>
*/
#ifdef __UTIL_POLYNOMIAL_IPP
#error "twice included ipp"
#endif
#define __UTIL_POLYNOMIAL_IPP
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T, typename U>
T
util::polynomial::eval (const std::array<T,S> coeffs, const U x)
{
U x_ = 1.f;
T sum {0.f};
for (size_t i = 0; i < S; ++i) {
sum += coeffs[S-i-1] * x_;
x_ *= x;
}
return sum;
}

View File

@ -14,12 +14,14 @@
* Copyright 2011-2016 Danny Robson <danny@nerdcruft.net> * Copyright 2011-2016 Danny Robson <danny@nerdcruft.net>
*/ */
#ifndef __UTIL_POOL_HPP #ifndef CRUFT_UTIL_POOL_HPP
#define __UTIL_POOL_HPP #define CRUFT_UTIL_POOL_HPP
#include "nocopy.hpp" #include "nocopy.hpp"
#include "debug.hpp"
#include <cstdlib> #include <cstdlib>
#include <cstdint>
namespace util { namespace util {
/// a simple pre-allocated pool for storage of PODs. /// a simple pre-allocated pool for storage of PODs.
@ -42,19 +44,85 @@ namespace util {
public: public:
explicit explicit
pool (unsigned int _capacity); pool (unsigned int _capacity):
m_capacity (_capacity),
m_size (0u)
{
static_assert (sizeof (T) >= sizeof (uintptr_t),
"pool<T>'s chained block system requires that T be at least pointer sized");
~pool (); // allocate the memory and note the base address for deletion in destructor
m_next = m_head = new node[m_capacity]; // static_cast<node *> (operator new (sizeof (T) * m_capacity));
// initialise the linked list of nodes
for (unsigned int i = 0; i < m_capacity - 1; ++i)
m_next[i]._node = m_next + i + 1;
m_next[m_capacity - 1]._node = nullptr;
}
~pool ()
{
// don't check if everything's been returned as pools are often used
// for PODs which don't need to be destructed via calling release.
delete [] m_head;
}
// Data management // Data management
template <typename ...Args> template <typename ...Args>
T* acquire (Args&... args); T* acquire (Args&... args)
{
// double check we have enough capacity left
if (!m_next)
throw std::bad_alloc ();
CHECK_LT (m_size, m_capacity);
void release (T *data); // save what will become the next node shortly. it could be overwritten
// in the constructor we're about to call.
node *newnext = m_next->_node;
T *data = reinterpret_cast<T*> (m_next);
size_t capacity (void) const; // try to construct the returnable object.
size_t size (void) const; try {
bool empty (void) const; new (data) T (args...);
} catch (...) {
// the constructor may have overwritten the node linkages before
// throwing. fix this up before forwarding the exception.
m_next->_node = newnext;
throw;
}
// the object is valid. save the new linked list head and bump the
// stats for availability.
m_next = newnext;
m_size++;
return data;
}
void release (T *data)
{
CHECK_NEZ (m_size);
data->~T();
node *newnode = reinterpret_cast<node *> (data);
newnode->_node = m_next;
m_next = newnode;
m_size--;
}
size_t capacity (void) const
{
return m_capacity;
}
size_t size (void) const
{
return m_size;
}
bool empty (void) const
{
return m_size == m_capacity;
}
// Indexing // Indexing
size_t index (const T*) const; size_t index (const T*) const;
@ -64,6 +132,5 @@ namespace util {
}; };
} }
#include "pool.ipp"
#endif // __UTIL_POOL_HPP #endif

138
pool.ipp
View File

@ -1,138 +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 2011-2016 Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_POOL_IPP
#error
#endif
#define __UTIL_POOL_IPP
#include "debug.hpp"
#include <cstdint>
#include <new>
#include <string>
namespace util {
//-------------------------------------------------------------------------
template <typename T>
pool<T>::pool (unsigned int _capacity):
m_capacity (_capacity),
m_size (0u)
{
static_assert (sizeof (T) >= sizeof (uintptr_t),
"pool<T>'s chained block system requires that T be at least pointer sized");
// allocate the memory and note the base address for deletion in destructor
m_next = m_head = new node[m_capacity]; // static_cast<node *> (operator new (sizeof (T) * m_capacity));
// initialise the linked list of nodes
for (unsigned int i = 0; i < m_capacity - 1; ++i)
m_next[i]._node = m_next + i + 1;
m_next[m_capacity - 1]._node = nullptr;
}
//-------------------------------------------------------------------------
template <typename T>
pool<T>::~pool ()
{
// don't check if everything's been returned as pools are often used
// for PODs which don't need to be destructed via calling release.
delete [] m_head;
}
//-------------------------------------------------------------------------
template <typename T>
size_t
pool<T>::capacity (void) const
{
return m_capacity;
}
//-------------------------------------------------------------------------
template <typename T>
size_t
pool<T>::size (void) const
{
return m_size;
}
//-------------------------------------------------------------------------
template <typename T>
bool
pool<T>::empty (void) const
{
return m_size == m_capacity;
}
//-------------------------------------------------------------------------
template <typename T>
template <typename ...Args>
T*
pool<T>::acquire (Args&... args)
{
// double check we have enough capacity left
if (!m_next)
throw std::bad_alloc ();
CHECK_LT (m_size, m_capacity);
// save what will become the next node shortly. it could be overwritten
// in the constructor we're about to call.
node *newnext = m_next->_node;
T *data = reinterpret_cast<T*> (m_next);
// try to construct the returnable object.
try {
new (data) T (args...);
} catch (...) {
// the constructor may have overwritten the node linkages before
// throwing. fix this up before forwarding the exception.
m_next->_node = newnext;
throw;
}
// the object is valid. save the new linked list head and bump the
// stats for availability.
m_next = newnext;
m_size++;
return data;
}
//-------------------------------------------------------------------------
template <typename T>
void
pool<T>::release (T *data)
{
CHECK_NEZ (m_size);
data->~T();
node *newnode = reinterpret_cast<node *> (data);
newnode->_node = m_next;
m_next = newnode;
m_size--;
}
}

View File

@ -17,11 +17,15 @@
#ifndef __UTIL_POSIX_DIR_HPP #ifndef __UTIL_POSIX_DIR_HPP
#define __UTIL_POSIX_DIR_HPP #define __UTIL_POSIX_DIR_HPP
#include "except.hpp"
#include <cerrno>
#include <dirent.h> #include <dirent.h>
#include <functional> #include <functional>
#include <experimental/filesystem> #include <experimental/filesystem>
namespace util::posix { namespace util::posix {
struct dir { struct dir {
public: public:
@ -30,13 +34,18 @@ namespace util::posix {
operator DIR* (void); operator DIR* (void);
template <typename ...Args> // run a callback for each entry in the provided directory
template <typename FunctionT, typename ...Args>
void void
scan (std::function<void(const std::experimental::filesystem::path&, Args&...)>, Args&...); scan (FunctionT &&func, Args&&...args)
{
rewind ();
template <typename ...Args> for (dirent *cursor; errno = 0, cursor = readdir (m_handle); )
void func (cursor->d_name, args...);
scan (void (*) (const std::experimental::filesystem::path&, Args&...), Args&...);
error::try_code ();
}
//entry begin (void) { rewind (); return { readdir (m_handle), m_handle }; } //entry begin (void) { rewind (); return { readdir (m_handle), m_handle }; }
//entry end (void) { return { nullptr, m_handle }; } //entry end (void) { return { nullptr, m_handle }; }
@ -48,6 +57,4 @@ namespace util::posix {
}; };
} }
#include "dir.ipp"
#endif #endif

View File

@ -1,47 +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-2016 Danny Robson <danny@nerdcruft.net>
*/
#include "except.hpp"
#include <cerrno>
///////////////////////////////////////////////////////////////////////////////
template <typename ...Args>
void
util::posix::dir::scan(std::function<void(const std::experimental::filesystem::path&, Args&...)> cb, Args &...args)
{
rewind ();
for (dirent *cursor; errno = 0, cursor = readdir (m_handle); )
cb (cursor->d_name, args...);
error::try_code ();
}
//-----------------------------------------------------------------------------
template <typename ...Args>
void
util::posix::dir::scan (void (*cb) (const std::experimental::filesystem::path&, Args&...), Args &...args)
{
rewind ();
for (dirent *cursor; errno = 0, cursor = readdir (m_handle); )
cb (cursor->d_name, args...);
error::try_code ();
}

View File

@ -19,6 +19,7 @@
#include "coord/traits.hpp" #include "coord/traits.hpp"
#include "maths.hpp"
#include "vector.hpp" #include "vector.hpp"
#include "matrix.hpp" #include "matrix.hpp"
@ -48,10 +49,15 @@ namespace util {
matrix4<T> as_matrix (void) const; matrix4<T> as_matrix (void) const;
static constexpr quaternion<T> identity (void); static constexpr
quaternion<T> identity (void)
{
return { 1, 0, 0, 0 };
}
}; };
//-------------------------------------------------------------------------
template <typename T> template <typename T>
struct arity<quaternion<T>,void> struct arity<quaternion<T>,void>
:std::integral_constant<std::size_t, 4> :std::integral_constant<std::size_t, 4>
@ -68,22 +74,43 @@ namespace util {
template <typename T> template <typename T>
constexpr constexpr
T T
norm2 (quaternion<T>); norm2 (quaternion<T> q)
{
return q.w * q.w +
q.x * q.x +
q.y * q.y +
q.z * q.z;
}
//-------------------------------------------------------------------------
template <typename T> template <typename T>
constexpr constexpr
T T
norm (quaternion<T>); norm (quaternion<T> q)
{
return std::sqrt (norm2 (q));
}
//-------------------------------------------------------------------------
template <typename T> template <typename T>
constexpr constexpr
bool bool
is_normalised (quaternion<T>); is_normalised (quaternion<T> q)
{
return almost_equal (T{1}, norm2 (q));
}
//-------------------------------------------------------------------------
template <typename T> template <typename T>
constexpr constexpr
quaternion<T> quaternion<T>
normalised (quaternion<T>); normalised (quaternion<T> q)
{
return q / norm (q);
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -97,32 +124,46 @@ namespace util {
quaternion<T> quaternion<T>
operator* (quaternion<T>, quaternion<T>); operator* (quaternion<T>, quaternion<T>);
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
template <typename T> template <typename T>
quaternion<T>& quaternion<T>&
operator*= (quaternion<T>&, quaternion<T>); operator*= (quaternion<T>&, quaternion<T>);
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
template <typename T> template <typename T>
quaternion<T> quaternion<T>
operator/ (quaternion<T>, quaternion<T>); operator/ (quaternion<T>, quaternion<T>);
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
template <typename T> template <typename T>
constexpr constexpr
quaternion<T> quaternion<T>
operator/ (quaternion<T>, T); operator/ (quaternion<T> q, T t)
{
return { q.w / t, q.x / t, q.y / t, q.z / t };
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
template <typename T> template <typename T>
constexpr constexpr
bool operator== (quaternion<T>, quaternion<T>); bool operator== (quaternion<T> a, quaternion<T> b)
{
return exactly_equal (a.w, b.w) &&
exactly_equal (a.x, b.x) &&
exactly_equal (a.y, b.y) &&
exactly_equal (a.z, b.z);
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
template <typename T> template <typename T>
bool almost_equal (quaternion<T>, quaternion<T>); bool almost_equal (quaternion<T>, quaternion<T>);
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
typedef quaternion<float> quaternionf; typedef quaternion<float> quaternionf;
typedef quaternion<double> quaterniond; typedef quaternion<double> quaterniond;
@ -134,6 +175,4 @@ namespace util {
operator<< (std::ostream&, quaternion<T>); operator<< (std::ostream&, quaternion<T>);
} }
#include "quaternion.ipp"
#endif #endif

View File

@ -1,99 +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 2011-2016 Danny Robson <danny@nerdcruft.net>
*/
#if defined(CRUFT_UTIL_QUATERNION_IPP)
#error
#endif
#define CRUFT_UTIL_QUATERNION_IPP
#include <cmath>
///////////////////////////////////////////////////////////////////////////////
template <typename T>
constexpr
util::quaternion<T>
util::quaternion<T>::identity (void)
{
return { 1, 0, 0, 0 };
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
constexpr
T
util::norm2 (quaternion<T> q)
{
return q.w * q.w +
q.x * q.x +
q.y * q.y +
q.z * q.z;
}
//-----------------------------------------------------------------------------
template <typename T>
constexpr
T
util::norm (quaternion<T> q)
{
return std::sqrt (norm2 (q));
}
//-----------------------------------------------------------------------------
template <typename T>
constexpr
bool
util::is_normalised (quaternion<T> q)
{
return almost_equal (T{1}, norm2 (q));
}
//-----------------------------------------------------------------------------
template <typename T>
constexpr
util::quaternion<T>
util::normalised (quaternion<T> q)
{
return q / norm (q);
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
constexpr
util::quaternion<T>
util::operator/ (quaternion<T> q, T t)
{
return { q.w / t, q.x / t, q.y / t, q.z / t };
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
constexpr
bool
util::operator== (quaternion<T> a, quaternion<T> b)
{
return exactly_equal (a.w, b.w) &&
exactly_equal (a.x, b.x) &&
exactly_equal (a.y, b.y) &&
exactly_equal (a.z, b.z);
}

View File

@ -20,6 +20,8 @@
#include <cstdint> #include <cstdint>
#include <ostream> #include <ostream>
#include <limits>
#include <type_traits>
namespace util { namespace util {
/** /**
@ -55,7 +57,15 @@ namespace util {
/// bounds, it is the caller's responsibility to clamp the result if /// bounds, it is the caller's responsibility to clamp the result if
/// needed. /// needed.
template <typename U> template <typename U>
U normalise (T val) const; U
normalise (T val) const
{
static_assert (std::is_floating_point<U>::value,
"normalise isn't implemented for integer types");
return static_cast<U> (val - lo) /
static_cast<U> ( hi - lo);
}
range& operator*= (T); range& operator*= (T);
range operator* (T) const; range operator* (T) const;
@ -78,10 +88,32 @@ namespace util {
{ return !(*this == rhs); } { return !(*this == rhs); }
/// A range which is guaranteed to contain all elements type T /// A range which is guaranteed to contain all elements type T
static constexpr range<T> unlimited (void); static constexpr range<T> unlimited (void)
static constexpr range<T> max (void); {
return {
std::numeric_limits<T>::has_infinity ? -std::numeric_limits<T>::infinity () :
std::numeric_limits<T>::lowest (),
std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity () :
std::numeric_limits<T>::max ()
};
}
static constexpr range<T> max (void)
{
return {
std::numeric_limits<T>::lowest (),
std::numeric_limits<T>::max ()
};
}
/// A range which only contains elements between 0 and 1 inclusive /// A range which only contains elements between 0 and 1 inclusive
static constexpr range<T> unit (void); static constexpr range<T> unit (void)
{
return {
T {0}, T {1}
};
}
void sanity (void) const; void sanity (void) const;
}; };
@ -101,6 +133,4 @@ namespace util {
} }
} }
#include "range.ipp"
#endif #endif

View File

@ -1,78 +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 2010-2015 Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_RANGE_IPP
#error
#else
#define __UTIL_RANGE_IPP
#endif
#include <limits>
#include <type_traits>
//-----------------------------------------------------------------------------
template <typename T>
template <typename U>
U
util::range<T>::normalise (T val) const
{
static_assert (std::is_floating_point<U>::value,
"normalise isn't implemented for integer types");
return static_cast<U> (val - lo) /
static_cast<U> ( hi - lo);
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
constexpr
util::range<T>
util::range<T>::unlimited (void)
{
return {
std::numeric_limits<T>::has_infinity ? -std::numeric_limits<T>::infinity () :
std::numeric_limits<T>::lowest (),
std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity () :
std::numeric_limits<T>::max ()
};
}
//-----------------------------------------------------------------------------
template <typename T>
constexpr
util::range<T>
util::range<T>::max (void)
{
return {
std::numeric_limits<T>::lowest (),
std::numeric_limits<T>::max ()
};
}
//-----------------------------------------------------------------------------
template <typename T>
constexpr
util::range<T>
util::range<T>::unit (void)
{
return {
T {0}, T {1}
};
}

View File

@ -51,15 +51,24 @@ namespace util {
T d; T d;
}; };
template <typename T, typename U>
rational<typename std::common_type<T,U>::type>
operator/ (U, rational<T>);
///////////////////////////////////////////////////////////////////////////
template <typename T, typename U> template <typename T, typename U>
rational<typename std::common_type<T,U>::type> rational<typename std::common_type<T,U>::type>
operator* (U, rational<T>); operator/ (U lhs, rational<T> rhs)
{
return rhs.inverse () * lhs;
} }
#include "rational.ipp"
//-------------------------------------------------------------------------
template <typename T, typename U>
rational<typename std::common_type<T,U>::type>
operator* (U lhs, rational<T> rhs)
{
return rhs * lhs;
}
};
#endif #endif

View File

@ -1,38 +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>
*/
#ifdef __UTIL_RATIONAL_IPP
#error
#endif
#define __UTIL_RATIONAL_IPP
//-----------------------------------------------------------------------------
template <typename T, typename U>
util::rational<typename std::common_type<T,U>::type>
util::operator/ (U lhs, rational<T> rhs)
{
return rhs.inverse () * lhs;
}
//-----------------------------------------------------------------------------
template <typename T, typename U>
util::rational<typename std::common_type<T,U>::type>
util::operator* (U lhs, rational<T> rhs)
{
return rhs * lhs;
}

View File

@ -51,7 +51,14 @@ namespace util {
//--------------------------------------------------------------------- //---------------------------------------------------------------------
template <typename U> template <typename U>
constexpr region<S,U> cast (void) const; constexpr region<S,U>
cast (void) const
{
return {
p.template cast<U> (),
e.template cast<U> ()
};
}
//--------------------------------------------------------------------- //---------------------------------------------------------------------
T area (void) const; T area (void) const;
@ -114,8 +121,21 @@ namespace util {
{ return !(*this == rhs); } { return !(*this == rhs); }
// Utility constants // Utility constants
static constexpr region<S,T> max (void); static constexpr region<S,T> max (void)
static constexpr region<S,T> unit (void); {
return {
util::point <S,T> {std::numeric_limits<T>::lowest () / 2},
util::extent<S,T> {std::numeric_limits<T>::max ()}
};
}
static constexpr region<S,T> unit (void)
{
return {
point_t::origin (),
extent_t {1}
};
}
static constexpr region<S,T> zero (void) static constexpr region<S,T> zero (void)
{ return { point_t {0}, extent_t {0} }; } { return { point_t {0}, extent_t {0} }; }
@ -231,6 +251,4 @@ namespace util {
std::ostream& operator<< (std::ostream&, const util::region<S,T>&); std::ostream& operator<< (std::ostream&, const util::region<S,T>&);
} }
#include "region.ipp"
#endif #endif

View File

@ -1,59 +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 2010-2015 Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_REGION_IPP
#error
#endif
#define __UTIL_REGION_IPP
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
template <typename U>
constexpr util::region<S,U>
util::region<S,T>::cast (void) const
{
return {
p.template cast<U> (),
e.template cast<U> ()
};
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
constexpr
util::region<S,T>
util::region<S,T>::max (void)
{
return {
util::point <S,T> {std::numeric_limits<T>::lowest () / 2},
util::extent<S,T> {std::numeric_limits<T>::max ()}
};
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
constexpr
util::region<S,T>
util::region<S,T>::unit (void)
{
return {
point_t::origin (),
extent_t {1}
};
}

View File

@ -14,11 +14,14 @@
* Copyright 2011-2015 Danny Robson <danny@nerdcruft.net> * Copyright 2011-2015 Danny Robson <danny@nerdcruft.net>
*/ */
#ifndef __UTIL_SIGNAL_HPP #ifndef CRUFT_UTIL_SIGNAL_HPP
#define __UTIL_SIGNAL_HPP #define CRUFT_UTIL_SIGNAL_HPP
#include "types/traits.hpp" #include "types/traits.hpp"
#include "debug.hpp"
#include "nocopy.hpp"
#include <algorithm>
#include <functional> #include <functional>
#include <list> #include <list>
@ -77,50 +80,137 @@ namespace util {
struct cookie; struct cookie;
public: public:
signal (); signal () = default;
~signal (); ~signal ()
{
CHECK (empty ());
}
/// Add a callback to list. /// Add a callback to list.
cookie connect [[nodiscard]] (callback&&); cookie connect [[nodiscard]] (callback &&_cb)
cookie connect [[nodiscard]] (const callback&); {
return cookie (
m_children.insert (
m_children.end (),
std::move (_cb)
),
*this
);
}
void disconnect (cookie&); cookie connect [[nodiscard]] (const callback &_cb)
{
{
return cookie (
m_children.insert (
m_children.end (),
std::move (_cb)
),
*this
);
}
}
void disconnect (cookie &c)
{
m_children.erase (c.m_position);
c.m_position = m_children.end ();
}
/// Disconnect all callbacks /// Disconnect all callbacks
void clear (void); void clear (void)
{
m_children.clear ();
}
/// Returns the number of callbacks connected. /// Returns the number of callbacks connected.
size_t size (void) const; size_t size (void) const
bool empty (void) const; {
return m_children.size ();
}
bool empty (void) const
{
return m_children.empty ();
}
/// Execute all callbacks /// Execute all callbacks
template <typename ...Args> template <typename ...Args>
R R
operator() (Args&&... tail); operator() (Args&&... tail)
{
if (m_children.empty ())
return R();
C<F> combiner;
return combiner (
m_children.begin (),
m_children.end (),
std::forward<Args> (tail)...
);
}
private: private:
typedef std::list<callback> group; typedef std::list<callback> group;
group m_children; group m_children;
}; };
///////////////////////////////////////////////////////////////////////////
template <typename F, template <typename> class C>
struct signal<F,C>::cookie : public nocopy {
cookie (typename group::iterator _position,
signal<F,C> &_parent):
m_position (_position),
m_parent (_parent)
{ ; }
cookie (cookie &&rhs):
m_position (rhs.m_position),
m_parent (rhs.m_parent)
{
rhs.m_position = rhs.m_parent.m_children.end ();
}
~cookie ()
{
if (m_parent.m_children.end () != m_position)
m_parent.disconnect (*this);
}
void reset (callback &&cb)
{
*m_position = std::move (cb);
}
typename group::iterator m_position;
signal<F,C> &m_parent;
};
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// wrap a value in a signal and trigger on assignment // wrap a value in a signal and trigger on assignment
//template <typename T, template <typename> class C> //template <typename T, template <typename> class C>
template <typename T> template <typename T>
class value_signal : public signal<void(T)> { class value_signal : public signal<void(T)> {
public: public:
explicit value_signal (T); explicit value_signal (T t): m_value (t) { ; }
value_signal () = default; value_signal () = default;
operator const T&() const; operator const T&() const { return m_value; }
value_signal<T>& operator= (const T&); value_signal<T>&
operator= (const T &t)
{
m_value = t;
(*this) (m_value);
return *this;
}
private: private:
T m_value; T m_value;
}; };
} }
#include "signal.ipp" #endif
#endif // __SIGNAL_HPP

View File

@ -1,202 +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 2011-2015 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_SIGNAL_HPP
#error
#endif
#include "debug.hpp"
#include "nocopy.hpp"
#include <algorithm>
namespace util {
///////////////////////////////////////////////////////////////////////////
template <typename F, template <typename> class C>
struct signal<F,C>::cookie : public nocopy {
cookie (typename group::iterator, signal<F,C> &parent);
cookie (cookie &&rhs);
~cookie ();
void reset (callback &&cb);
typename group::iterator m_position;
signal<F,C> &m_parent;
};
///////////////////////////////////////////////////////////////////////////
template <typename F, template <typename> class C>
signal<F,C>::cookie::cookie (typename group::iterator _position,
signal<F,C> &_parent):
m_position (_position),
m_parent (_parent)
{ ; }
//-------------------------------------------------------------------------
template <typename F, template <typename> class C>
signal<F,C>::cookie::cookie (cookie &&rhs):
m_position (rhs.m_position),
m_parent (rhs.m_parent)
{
rhs.m_position = rhs.m_parent.m_children.end ();
}
//-------------------------------------------------------------------------
template <typename F, template <typename> class C>
signal<F,C>::cookie::~cookie ()
{
if (m_parent.m_children.end () != m_position)
m_parent.disconnect (*this);
}
///////////////////////////////////////////////////////////////////////////
template <typename F, template <typename> class C>
void
signal<F,C>::cookie::reset (callback &&cb)
{
*m_position = std::move (cb);
}
///////////////////////////////////////////////////////////////////////////
template <typename F, template <typename> class C>
signal<F,C>::signal ()
{ ; }
//-------------------------------------------------------------------------
template <typename F, template <typename> class C>
signal<F,C>::~signal ()
{
CHECK (empty ());
}
///////////////////////////////////////////////////////////////////////////
template <typename F, template <typename> class C>
typename signal<F,C>::cookie
signal<F,C>::connect (const callback &_cb)
{
return cookie (
m_children.insert (
m_children.end (),
std::move (_cb)
),
*this
);
}
//-------------------------------------------------------------------------
template <typename F, template <typename> class C>
typename signal<F,C>::cookie
signal<F,C>::connect (callback &&_cb)
{
return cookie (
m_children.insert (
m_children.end (),
std::move (_cb)
),
*this
);
}
//-------------------------------------------------------------------------
template <typename F, template <typename> class C>
void
signal<F,C>::disconnect (cookie &c)
{
m_children.erase (c.m_position);
c.m_position = m_children.end ();
}
//-------------------------------------------------------------------------
/// Disconnect all callbacks
template <typename F, template <typename> class C>
void
signal<F,C>::clear (void)
{
m_children.clear ();
}
///////////////////////////////////////////////////////////////////////////
/// Returns the number of callbacks connected.
template <typename F, template <typename> class C>
size_t
signal<F,C>::size (void) const
{
return m_children.size ();
}
//-------------------------------------------------------------------------
template <typename F, template <typename> class C>
bool
signal<F,C>::empty (void) const
{
return m_children.empty ();
}
///////////////////////////////////////////////////////////////////////////
template <typename F, template <typename> class C>
template <typename ...Args>
typename signal<F,C>::R
signal<F,C>::operator () (Args&&... tail) {
if (m_children.empty ())
return R();
C<F> combiner;
return combiner (
m_children.begin (),
m_children.end (),
std::forward<Args> (tail)...
);
}
///////////////////////////////////////////////////////////////////////////
template <typename T>
value_signal<T>::value_signal (T t):
m_value (t)
{ ; }
//-------------------------------------------------------------------------
template <typename T>
value_signal<T>::operator const T&() const
{
return m_value;
}
//-------------------------------------------------------------------------
template <typename T>
value_signal<T>&
value_signal<T>::operator= (const T &t)
{
m_value = t;
(*this) (m_value);
return *this;
}
}

View File

@ -35,24 +35,37 @@ namespace util {
using coord::base<S,T,vector<S,T>>::base; using coord::base<S,T,vector<S,T>>::base;
// representations // representations
template <size_t D> vector<D,T> homog (void) const; template <size_t D> vector<D,T> homog (void) const
{
static_assert (D > S, "reducing size loses data");
return (*this).template redim<D> (0.f);
}
// constants // constants
static constexpr vector<S,T> ones (void); static constexpr vector<S,T> ones (void) { return vector<S,T> {1}; }
static constexpr vector<S,T> zeros (void); static constexpr vector<S,T> zeros (void) { return vector<S,T> {0}; }
void sanity (void) const; void sanity (void) const;
}; };
template <typename T> template <typename T>
constexpr constexpr vector<3,T>
vector<3,T> cross (vector<3,T> a, vector<3,T> b)
cross (vector<3,T>, vector<3,T>); {
return {
a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x
};
}
template <typename T> template <typename T>
constexpr constexpr
T T
cross (vector<2,T>, vector<2,T>); cross (vector<2,T> a, vector<2,T> b)
{
return a[0] * b[1] - a[1] * b[0];
}
// polar/cartesian conversions; assumes (mag, angle) form. // polar/cartesian conversions; assumes (mag, angle) form.
template <typename T> vector<2,T> polar_to_cartesian (vector<2,T>); template <typename T> vector<2,T> polar_to_cartesian (vector<2,T>);
@ -145,7 +158,5 @@ namespace util {
using vector4b = vector4<bool>; using vector4b = vector4<bool>;
} }
#include "vector.ipp"
#endif #endif

View File

@ -1,78 +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 2011-2016 Danny Robson <danny@nerdcruft.net>
*/
#if defined(__UTIL_VECTOR_IPP)
#error
#else
#define __UTIL_VECTOR_IPP
#endif
#include "maths.hpp"
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
template <size_t D>
util::vector<D,T>
util::vector<S,T>::homog (void) const
{
static_assert (D > S, "reducing size loses data");
return (*this).template redim<D> (0.f);
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
constexpr
util::vector<3,T>
util::cross (util::vector<3,T> a, util::vector<3,T> b)
{
return {
a.y * b.z - a.z * b.y,
a.z * b.x - a.x * b.z,
a.x * b.y - a.y * b.x
};
}
//-----------------------------------------------------------------------------
template <typename T>
constexpr
T
util::cross (util::vector<2,T> a, util::vector<2,T> b)
{
return a[0] * b[1] - a[1] * b[0];
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
constexpr
util::vector<S,T>
util::vector<S,T>::ones (void)
{
return vector<S,T> {1};
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
constexpr
util::vector<S,T>
util::vector<S,T>::zeros (void)
{
return vector<S,T> {0};
}