Merge remote-tracking branch 'origin/master'

This commit is contained in:
Danny Robson 2016-10-02 16:13:31 +11:00
commit 152a55ad78
119 changed files with 3161 additions and 3573 deletions

View File

@ -32,6 +32,8 @@ UTIL_FILES = \
alloc/null.hpp \
alloc/stack.cpp \
alloc/stack.hpp \
annotation.hpp \
ascii.hpp \
backtrace.hpp \
bezier.cpp \
bezier.hpp \
@ -44,6 +46,7 @@ UTIL_FILES = \
colour.cpp \
colour.hpp \
colour.ipp \
coord/fwd.hpp \
coord/base.hpp \
coord.hpp \
coord/init.hpp \
@ -162,8 +165,6 @@ UTIL_FILES = \
io.cpp \
io.hpp \
io.ipp \
ip.cpp \
ip.hpp \
iterator.hpp \
json/fwd.hpp \
json/except.cpp \
@ -274,14 +275,6 @@ UTIL_FILES = \
POSIX_FILES = \
net/address.cpp \
net/address.hpp \
net/except.cpp \
net/except.hpp \
net/socket.cpp \
net/socket.hpp \
net/types.cpp \
net/types.hpp \
memory/buffer/circular.cpp \
memory/buffer/circular.hpp \
memory/buffer/paged.cpp \
@ -348,8 +341,8 @@ BACKTRACE_FILES=$(firstword $(__BACKTRACE_FILES) backtrace_null.cpp)
###############################################################################
## Local build rules
CLEANFILES = json.cpp version.cpp ip.cpp uri.cpp
EXTRA_DIST = json/flat.cpp.rl version.cpp.rl ip.cpp.rl uri.cpp.rl
CLEANFILES = json.cpp version.cpp uri.cpp
EXTRA_DIST = json/flat.cpp.rl version.cpp.rl uri.cpp.rl
RAGELFLAGS = -F1
SUFFIXES = .cpp .cpp.rl
@ -394,6 +387,7 @@ TEST_BIN = \
test/alloc/dynamic \
test/alloc/linear \
test/alloc/stack \
test/affine \
test/backtrace \
test/bezier \
test/bitwise \
@ -426,7 +420,6 @@ TEST_BIN = \
test/hash/sha2 \
test/hton \
test/introspection \
test/ip \
test/json_types \
test/maths \
test/matrix \
@ -434,6 +427,7 @@ TEST_BIN = \
test/point \
test/polynomial \
test/pool \
test/quaternion \
test/rand/buckets \
test/random \
test/range \

33
annotation.hpp Normal file
View File

@ -0,0 +1,33 @@
/*
* 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 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_ANNOTATION_HPP
#define __UTIL_ANNOTATION_HPP
template <typename T>
constexpr inline
bool
likely (T &&t)
{ return __builtin_expect (!!t, true); }
template <typename T>
constexpr inline
bool
unlikely (T &&t)
{ return __builtin_expect (!!t, false); }
#endif

92
ascii.hpp Normal file
View File

@ -0,0 +1,92 @@
/*
* 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>
*/
#ifndef __CRUFT_UTIL_ASCII_HPP
#define __CRUFT_UTIL_ASCII_HPP
#include "./annotation.hpp"
#include <cstdint>
#include <stdexcept>
namespace util { namespace ascii {
///////////////////////////////////////////////////////////////////////////
constexpr inline
bool
is_digit (char c) noexcept
{
return c >= '0' && c <= '9';
}
//-------------------------------------------------------------------------
constexpr inline
uint8_t
to_integer (char c)
{
return likely (is_digit (c)) ?
c - '0'
: throw std::invalid_argument ("character is not a digit");
}
//-------------------------------------------------------------------------
constexpr inline
bool
is_upper (char c) noexcept
{
return c >= 'A' && c <= 'Z';
}
///////////////////////////////////////////////////////////////////////////
constexpr inline
char
to_upper (char c) noexcept
{
return c - 'a' + 'A';
}
//-------------------------------------------------------------------------
constexpr inline
char
to_lower (char c) noexcept
{
return c - 'A' + 'a';
}
///////////////////////////////////////////////////////////////////////////
constexpr inline
bool
is_space (char c)
{
switch (c) {
case ' ':
case '\f':
case '\n':
case '\r':
case '\t':
case '\v':
return true;
default:
return false;
}
}
} }
#endif

View File

@ -41,7 +41,7 @@ debug::backtrace::backtrace (void):
while ((last = ::backtrace (&m_frames[0], trunc_cast<int> (m_frames.size ()))) == size)
m_frames.resize (size = m_frames.size () * 2);
CHECK_GT (last, 0);
CHECK_GT (last, 0u);
m_frames.resize (last);
}
@ -81,7 +81,7 @@ debug::operator <<(std::ostream &os, const debug::backtrace &rhs) {
str_t names (backtrace_symbols (frames.data (), trunc_cast<int> (frames.size ())), ::free);
for (unsigned int i = 0; i < frames.size (); ++i)
os << frames[i] << '\t' << names.get()[i] << '\t' << addr2line (frames[i]) << '\n';
os << frames[i] << '\t' << names.get()[i] << '\t' << addr2line (frames[i]);
return os;
}

View File

@ -20,7 +20,7 @@
#include "point.hpp"
#include "region.hpp"
#include <iostream>
#include <ostream>
namespace util {
template <size_t S>

View File

@ -14,11 +14,12 @@
* Copyright 2010-2016 Danny Robson <danny@nerdcruft.net>
*/
#include "colour.hpp"
#include "./colour.hpp"
#include "range.hpp"
#include "random.hpp"
#include "stream.hpp"
#include "./debug.hpp"
#include "./range.hpp"
#include "./random.hpp"
#include "./stream.hpp"
#include <array>
#include <map>
@ -439,14 +440,38 @@ util::operator>> (std::istream &is, util::colour<S,T> &c)
template std::istream& util::operator>> (std::istream&, util::colour<3,uint8_t>&);
///////////////////////////////////////////////////////////////////////////////
#define INSTANTIATE_S_T(S,T) \
template struct util::colour<S,T>; \
template std::ostream& util::operator<< (std::ostream&, util::colour<S,T>);
// we need to instantiate the various type_name specialisations for colour.
//
// we provide a declaration here, before then instantiating a routine that we
// know will cause an implicit instantiation (ie util::to_string) for each
// colour specialisation we require.
template <size_t S, typename T>
constexpr
const char util::type_name<colour<S,T>>::value[];
//-----------------------------------------------------------------------------
#define INSTANTIATE_S_T(S,T) \
template \
struct util::colour<S,T>; \
\
template \
std::ostream& \
util::operator<< (std::ostream&, util::colour<S,T>); \
\
template \
const char* \
util::to_string<util::colour<S,T>> (void);
//-----------------------------------------------------------------------------
#define INSTANTIATE_S(S) \
INSTANTIATE_S_T(S,uint8_t) \
INSTANTIATE_S_T(S,float) \
INSTANTIATE_S_T(S,double)
//-----------------------------------------------------------------------------
INSTANTIATE_S(1)
INSTANTIATE_S(3)
INSTANTIATE_S(4)

View File

@ -18,8 +18,9 @@
#define __UTIL_COLOUR_HPP
#include "coord.hpp"
#include "introspection.hpp"
#include <iostream>
#include <ostream>
namespace util {
/// An RGBA colour POD type.
@ -28,6 +29,7 @@ namespace util {
using coord::base<S,T,util::colour,coord::rgba,coord::hsv>::base;
using base_t = coord::base<S,T,util::colour,coord::rgba,coord::hsv>;
// overloaded cast operator which assumes values are unit normalised
template <typename U>
colour<S,U>
cast (void) const;
@ -48,6 +50,7 @@ namespace util {
template <typename T> using colour3 = colour<3,T>;
template <typename T> using colour4 = colour<4,T>;
typedef colour1<uint8_t> colour1u;
typedef colour3<uint8_t> colour3u;
typedef colour4<uint8_t> colour4u;
@ -55,15 +58,24 @@ namespace util {
typedef colour3<float> colour3f;
typedef colour4<float> colour4f;
// RGB <-> HSV
// RGB/HSV conversions
colour3f rgb_to_hsv (colour3f);
colour3f hsv_to_rgb (colour3f);
// ostream/istream operators
template <size_t S, typename T>
std::ostream& operator<< (std::ostream&, util::colour<S,T>);
std::ostream&
operator<< (std::ostream&, util::colour<S,T>);
template <size_t S, typename T>
std::istream& operator>> (std::istream&, util::colour<S,T>&);
std::istream&
operator>> (std::istream&, util::colour<S,T>&);
// type name introspection specialisation
template <size_t S, typename T>
struct type_name<colour<S,T>> {
static constexpr const char value[] = "colour";
};
}
#include "colour.ipp"

View File

@ -21,6 +21,7 @@ NC_CXX
NC_PLATFORM
NC_OPTIMISATION
NC_WARNINGS
# NC_DEBUGGING is called further down, see notes at the call site.
LT_INIT
@ -83,8 +84,6 @@ AC_SEARCH_LIBS([clock_gettime], [rt c], [], [
AC_SEARCH_LIBS([cos], [m], [], [AC_MSG_ERROR([unable to find the maths library])])
AC_SEARCH_LIBS([htons], [ws2_32], [], [AC_MSG_ERROR([unable to find htons library])])
###############################################################################
## Debug features
@ -126,7 +125,7 @@ AC_SUBST(LIBS)
# failure on a clean build
AX_APPEND_FLAG([-include config.h])
NC_SUBPACKAGE([util])
NC_SUBPACKAGE([cruft-util])
AC_CONFIG_FILES([
Doxyfile

View File

@ -45,7 +45,7 @@ namespace util { namespace coord {
base () = default;
constexpr explicit base (T val)
{ for (size_t i = 0; i < S; ++i) this->data[i] = val; }
{ std::fill (begin (), end (), val); }
constexpr base (const base<S,T,KLASS,tags...> &rhs) = default;
base& operator= (const base<S,T,KLASS,tags...> &rhs) = default;
@ -54,6 +54,9 @@ namespace util { namespace coord {
T& operator[] (size_t i) { return this->data[i]; }
constexpr const T& operator[] (size_t i) const { return this->data[i]; }
auto cbegin (void) const { return std::cbegin (this->data); }
auto cend (void) const { return std::cend (this->data); }
auto begin (void) const { return std::begin (this->data); }
auto end (void) const { return std::end (this->data); }

28
coord/fwd.hpp Normal file
View File

@ -0,0 +1,28 @@
/*
* 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>
*/
#ifndef __UTIL_COORD_FWD_HPP
#define __UTIL_COORD_FWD_HPP
namespace util {
template <size_t,typename> struct colour;
template <size_t,typename> struct extent;
template <size_t,typename> struct point;
template <size_t,typename> struct quaternion;
template <size_t,typename> struct vector;
}
#endif

View File

@ -20,11 +20,23 @@
namespace util { namespace coord {
///////////////////////////////////////////////////////////////////////
// tags for accessor names
//
// colours
struct rgba { };
struct hsv { };
// physical positions
struct xyzw { };
// texture coords
struct stpq { };
// physical dimensions
struct whd { };
// quaternions
struct wxyz { };
struct abcd { };
} }
#endif

View File

@ -17,20 +17,16 @@
#ifndef __UTIL_COORDS_OPS
#define __UTIL_COORDS_OPS
#include "./fwd.hpp"
#include "../preprocessor.hpp"
#include "../maths.hpp"
#include "../types/bits.hpp"
#include <cstdlib>
#include <cmath>
#include <cstdlib>
namespace util {
// forward declerations for traits
template <size_t,typename> struct point;
template <size_t,typename> struct extent;
template <size_t,typename> struct vector;
template <size_t,typename> struct colour;
///////////////////////////////////////////////////////////////////////
// operation traits
namespace coord {
@ -38,26 +34,58 @@ namespace util {
template <size_t,typename> class A,
template <size_t,typename> class B
>
struct traits { };
struct result { };
//-------------------------------------------------------------------------
template <> struct traits<colour,colour> { template <size_t S, typename T> using result = colour<S,T>; };
template <> struct traits<extent,extent> { template <size_t S, typename T> using result = extent<S,T>; };
template <> struct traits<extent,vector> { template <size_t S, typename T> using result = extent<S,T>; };
template <> struct traits<point,extent> { template <size_t S, typename T> using result = point <S,T>; };
template <> struct traits<point,vector> { template <size_t S, typename T> using result = point <S,T>; };
template <> struct traits<vector,point> { template <size_t S, typename T> using result = point <S,T>; };
template <> struct traits<vector,vector> { template <size_t S, typename T> using result = vector<S,T>; };
template <> struct result<colour,colour> { template <size_t S, typename T> using type = colour<S,T>; };
template <> struct result<extent,extent> { template <size_t S, typename T> using type = extent<S,T>; };
template <> struct result<extent,vector> { template <size_t S, typename T> using type = extent<S,T>; };
template <> struct result<point,extent> { template <size_t S, typename T> using type = point <S,T>; };
template <> struct result<point,vector> { template <size_t S, typename T> using type = point <S,T>; };
template <> struct result<vector,point> { template <size_t S, typename T> using type = point <S,T>; };
template <> struct result<vector,vector> { template <size_t S, typename T> using type = vector<S,T>; };
template <
template <size_t,typename> class A,
template <size_t,typename> class B
>
using result_t = typename result<A,B>::type;
//---------------------------------------------------------------------
template <template <size_t,typename> class K>
struct has_norm : public std::false_type { };
template <> struct has_norm<vector> : public std::true_type { };
template <> struct has_norm<quaternion> : public std::true_type { };
template <template <size_t,typename> class K>
constexpr auto has_norm_v = has_norm<K>::value;
//---------------------------------------------------------------------
template <template <size_t,typename> class K>
struct has_scalar_op : public std::false_type { };
template <> struct has_scalar_op<colour> : public std::true_type { };
template <> struct has_scalar_op<extent> : public std::true_type { };
template <> struct has_scalar_op<point> : public std::true_type { };
template <> struct has_scalar_op<quaternion> : public std::true_type { };
template <> struct has_scalar_op<vector> : public std::true_type { };
template <template <size_t,typename> class K>
constexpr auto has_scalar_op_v = has_scalar_op<K>::value;
}
template <template <size_t,typename> class> struct is_coord : std::false_type { };
template <class> struct is_coord : std::false_type { };
template <> struct is_coord<point> : std::true_type { };
template <> struct is_coord<extent> : std::true_type { };
template <> struct is_coord<vector> : std::true_type { };
template <> struct is_coord<colour> : std::true_type { };
template <size_t S, typename T> struct is_coord<point<S,T>> : std::true_type { };
template <size_t S, typename T> struct is_coord<extent<S,T>> : std::true_type { };
template <size_t S, typename T> struct is_coord<vector<S,T>> : std::true_type { };
template <size_t S, typename T> struct is_coord<colour<S,T>> : std::true_type { };
template <size_t S, typename T> struct is_coord<quaternion<S,T>> : std::true_type { };
template <template <size_t,typename> class K>
template <class K>
constexpr bool
is_coord_v = is_coord<K>::value;
@ -71,7 +99,7 @@ namespace util {
template <size_t,typename> class A, \
template <size_t,typename> class B, \
typename = std::enable_if_t< \
is_coord_v<A> && is_coord_v<B>, \
is_coord_v<A<S,T>> && is_coord_v<B<S,U>>, \
void \
> \
> \
@ -79,7 +107,7 @@ namespace util {
auto \
operator OP (A<S,T> a, B<S,U> b) \
{ \
typename coord::traits<A,B>::template result< \
typename coord::result<A,B>::template type< \
S,std::common_type_t<T,U> \
> out {}; \
for (size_t i = 0; i < S; ++i) \
@ -94,8 +122,8 @@ namespace util {
template <size_t,typename> class A, \
template <size_t,typename> class B, \
typename = std::enable_if_t< \
is_coord_v<A> && \
is_coord_v<B> && \
is_coord_v<A<S,T>> && \
is_coord_v<B<S,U>> && \
std::is_same< \
std::common_type_t<T,U>, T \
>::value, \
@ -126,7 +154,7 @@ namespace util {
typename U, \
template <size_t,typename> class K, \
typename = std::enable_if_t< \
is_coord_v<K>,void \
coord::has_scalar_op_v<K>, void \
> \
> \
constexpr \
@ -146,7 +174,7 @@ namespace util {
typename U, \
template <size_t,typename> class K, \
typename = std::enable_if_t< \
is_coord<K>::value,void \
coord::has_scalar_op_v<K>,void \
> \
> \
constexpr \
@ -181,7 +209,7 @@ namespace util {
typename U, \
template <size_t,typename> class K, \
typename = std::enable_if_t< \
is_coord<K>::value && \
is_coord<K<S,T>>::value && \
std::is_arithmetic<T>::value && \
std::is_arithmetic<U>::value, \
void \
@ -219,7 +247,7 @@ namespace util {
typename T, \
template <size_t,typename> class K, \
typename = std::enable_if_t< \
is_coord_v<K>, void \
is_coord_v<K<S,T>>, void \
> \
> \
constexpr \
@ -251,7 +279,7 @@ namespace util {
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K>, void
is_coord_v<K<S,T>>, void
>
>
constexpr
@ -273,7 +301,7 @@ namespace util {
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K>, void
is_coord_v<K<S,T>>, void
>
>
constexpr
@ -284,6 +312,27 @@ namespace util {
}
//-------------------------------------------------------------------------
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K<S,T>>, void
>
>
constexpr
bool
almost_zero (const K<S,T> &k)
{
return std::all_of (
std::cbegin (k),
std::cend (k),
[] (T t) { return almost_equal (t); }
);
}
///////////////////////////////////////////////////////////////////////////
// special operators
@ -322,7 +371,7 @@ namespace util {
}
//-------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////
template <
size_t S,
typename T
@ -337,13 +386,15 @@ namespace util {
return sum;
}
//-------------------------------------------------------------------------
template <
size_t S,
typename T,
template <size_t,typename> class A,
template <size_t,typename> class B,
typename = std::enable_if_t<
is_coord_v<A> && is_coord_v<B>, void
is_coord_v<A<S,T>> && is_coord_v<B<S,T>>, void
>
>
constexpr
@ -354,12 +405,13 @@ namespace util {
}
//-------------------------------------------------------------------------
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K>, void
is_coord_v<K<S,T>>, void
>
>
constexpr
@ -370,12 +422,13 @@ namespace util {
}
//-------------------------------------------------------------------------
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K>, void
is_coord_v<K<S,T>>, void
>
>
constexpr
@ -386,13 +439,85 @@ namespace util {
}
///////////////////////////////////////////////////////////////////////////
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<coord::has_norm_v<K>,void>
>
constexpr
T
norm2 (const K<S,T> &k)
{
T sum = T{0};
for (auto &t: k)
sum += t * t;
return sum;
}
//-------------------------------------------------------------------------
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K>, void
coord::has_norm_v<K>,
void
>
>
constexpr
T
norm (const K<S,T> &k)
{
return std::sqrt (norm2 (k));
}
//-------------------------------------------------------------------------
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
coord::has_norm_v<K>,
void
>
>
constexpr
K<S,T>
normalised (const K<S,T> &k)
{
return k / norm (k);
}
//-------------------------------------------------------------------------
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
coord::has_norm_v<K>,
void
>
>
constexpr
bool
is_normalised (const K<S,T> &k)
{
return almost_equal (norm2 (k), T{1});
}
///////////////////////////////////////////////////////////////////////////
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K<S,T>>, void
>
>
constexpr
@ -404,13 +529,13 @@ namespace util {
return k;
}
//-------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K>, void
is_coord_v<K<S,T>>, void
>
>
constexpr
@ -422,6 +547,90 @@ namespace util {
return k;
}
///////////////////////////////////////////////////////////////////////////
// root of sum of squares
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K<S,T>>, void
>
>
constexpr
T
hypot (K<S,T> k)
{
return std::sqrt (sum (k * k));
}
///////////////////////////////////////////////////////////////////////////
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K<S,T>>, void
>
>
constexpr
K<S,T>
mod (K<S,T> k, T t)
{
std::transform (
std::cbegin (k),
std::cend (k),
std::begin (k),
[t] (auto v) { return mod (v, t);
});
return k;
}
///////////////////////////////////////////////////////////////////////////
// trigonometric functions
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<is_coord_v<K<S,T>>,void>
>
constexpr
K<S,T>
sin (K<S,T> k)
{
std::transform (
std::cbegin (k),
std::cend (k),
std::begin (k),
[] (auto v) { return std::sin (v); }
);
return k;
}
//-------------------------------------------------------------------------
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<is_coord_v<K<S,T>>,void>
>
constexpr
K<S,T>
cos (K<S,T> k)
{
std::transform (
std::cbegin (k),
std::cend (k),
std::begin (k),
[] (auto v) { return std::cos (v); }
);
return k;
}
///////////////////////////////////////////////////////////////////////////
// logical element operators
@ -432,7 +641,7 @@ namespace util {
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K>, void
is_coord_v<K<S,T>>, void
>
>
constexpr
@ -453,7 +662,7 @@ namespace util {
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K>, void
is_coord_v<K<S,T>>, void
>
>
constexpr
@ -473,7 +682,7 @@ namespace util {
typename T,
template<size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K>, void
is_coord_v<K<S,T>>, void
>
>
constexpr
@ -489,7 +698,7 @@ namespace util {
typename T,
template<size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K>, void
is_coord_v<K<S,T>>, void
>
>
constexpr
@ -500,32 +709,51 @@ namespace util {
}
//-------------------------------------------------------------------------
#define VECTOR_OP(OP) \
template < \
size_t S, \
typename T, \
typename U, \
template <size_t,typename> class A, \
template <size_t,typename> class B, \
typename = std::enable_if_t< \
is_coord_v<A> && is_coord_v<B>, void \
> \
> \
constexpr \
vector<S,bool> \
operator OP (const A<S,T> a, const B<S,U> b) \
{ \
vector<S,bool> out {}; \
for (size_t i = 0; i < S; ++i) \
out[i] = a[i] OP b[i]; \
return out; \
///////////////////////////////////////////////////////////////////////////
template <
size_t S,
typename T,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K<S,T>>, void
>
>
constexpr
T
sum (const K<S,T> k)
{
return sum (std::cbegin (k), std::cend (k));
}
///////////////////////////////////////////////////////////////////////////
#define VECTOR_OP(OP) \
template < \
size_t S, \
typename T, \
typename U, \
template <size_t,typename> class A, \
template <size_t,typename> class B, \
typename = std::enable_if_t< \
is_coord_v<A<S,T>> && is_coord_v<B<S,U>>, void \
> \
> \
constexpr \
vector<S,bool> \
operator OP (const A<S,T> a, const B<S,U> b) \
{ \
vector<S,bool> out {}; \
for (size_t i = 0; i < S; ++i) \
out[i] = a[i] OP b[i]; \
return out; \
}
VECTOR_OP(<)
VECTOR_OP(>)
VECTOR_OP(<=)
VECTOR_OP(>=)
VECTOR_OP(&&)
VECTOR_OP(||)
#undef VECTOR_OP
@ -537,7 +765,7 @@ namespace util {
typename U, \
template <size_t,typename> class K, \
typename = std::enable_if_t< \
is_coord_v<K>, void \
is_coord_v<K<S,T>>, void \
> \
> \
constexpr \
@ -554,6 +782,8 @@ namespace util {
SCALAR_OP(>)
SCALAR_OP(<=)
SCALAR_OP(>=)
SCALAR_OP(&&)
SCALAR_OP(||)
#undef SCALAR_OP
@ -563,7 +793,7 @@ namespace util {
size_t S,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K>, void
is_coord_v<K<S,bool>>, void
>
>
constexpr
@ -571,7 +801,7 @@ namespace util {
any (const K<S,bool> k)
{
return std::any_of (std::cbegin (k),
std::cbegin (k),
std::cend (k),
identity<bool>);
}
@ -580,7 +810,7 @@ namespace util {
size_t S,
template <size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K>, void
is_coord_v<K<S,bool>>, void
>
>
constexpr
@ -588,7 +818,7 @@ namespace util {
all (const K<S,bool> k)
{
return std::all_of (std::cbegin (k),
std::cbegin (k),
std::cend (k),
identity<bool>);
}
@ -599,7 +829,7 @@ namespace util {
typename T,
template<size_t,typename> class K,
typename = std::enable_if_t<
is_coord_v<K> && std::is_floating_point<T>::value, void
is_coord_v<K<S,T>> && std::is_floating_point<T>::value, void
>
>
constexpr

View File

@ -168,6 +168,17 @@ namespace util { namespace coord {
struct { T w,h,d; };
};
};
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct store<4,T,wxyz,abcd> {
union {
T data[4];
struct { T w,x,y,z; };
struct { T a,b,c,d; };
};
};
} }
#endif

116
debug.hpp
View File

@ -24,12 +24,10 @@
///////////////////////////////////////////////////////////////////////////////
#ifdef ENABLE_DEBUGGING
#define DEBUG_ONLY(X) do { \
X \
} while (0)
#if !defined(NDEBUG)
#define DEBUG_ONLY(X) do { X } while (0)
#else
#define DEBUG_ONLY(X)
#define DEBUG_ONLY(X) do { } while (0)
#endif
@ -41,14 +39,14 @@
///////////////////////////////////////////////////////////////////////////////
#define TRACE { \
DEBUG_ONLY( \
DEBUG_ONLY( \
std::cerr << __FILE__ << ":" << __func__ << ":" << __LINE__ << std::endl; \
); \
}
#define WARN(C) do { \
DEBUG_ONLY( \
DEBUG_ONLY( \
if (C) { \
std::cerr << __FILE__ << ":" << __func__ << ":" << __LINE__ << ", " << #C << std::endl; \
} \
@ -59,14 +57,14 @@
///////////////////////////////////////////////////////////////////////////////
#define _CHECK_PANIC(FMT,...) do { \
panic ("%s:%s:%i:%s\n" FMT, \
PACKAGE, __FILE__, __LINE__, __FUNCTION__, \
PACKAGE, __FILE__, __LINE__, __func__, \
__VA_ARGS__); \
} while(0)
///////////////////////////////////////////////////////////////////////////////
#define CHECK(C) do { \
DEBUG_ONLY( \
DEBUG_ONLY( \
if (!(C)) \
panic (#C); \
); \
@ -75,9 +73,9 @@
///////////////////////////////////////////////////////////////////////////////
#define CHECK_SANITY(A) do { \
DEBUG_ONLY( \
DEBUG_ONLY( \
const auto &__a = (A); \
if (!util::debug::valid (__a)) { \
if (!util::debug::is_valid (__a)) { \
_CHECK_PANIC("failed sanity test for %s, %!\n", #A, __a); \
} \
); \
@ -86,9 +84,9 @@
///////////////////////////////////////////////////////////////////////////////
#define CHECK_EQ(A,B) do { \
DEBUG_ONLY( \
const auto __a = (A); \
const auto __b = (B); \
DEBUG_ONLY( \
const auto &__a = (A); \
const auto &__b = (B); \
\
if (!util::almost_equal (__a, __b)) { \
_CHECK_PANIC("expected equality\n" \
@ -103,9 +101,9 @@
///////////////////////////////////////////////////////////////////////////////
#define CHECK_LT(A,B) do { \
DEBUG_ONLY( \
const auto __a = (A); \
const auto __b = (B); \
DEBUG_ONLY( \
const auto &__a = (A); \
const auto &__b = (B); \
\
if (__a >= __b) { \
_CHECK_PANIC("expected less than\n" \
@ -120,9 +118,9 @@
///////////////////////////////////////////////////////////////////////////////
#define CHECK_LE(A,B) do { \
DEBUG_ONLY( \
const auto __a = (A); \
const auto __b = (B); \
DEBUG_ONLY( \
const auto &__a = (A); \
const auto &__b = (B); \
\
if (__a > __b) { \
_CHECK_PANIC("expected less than or equal\n" \
@ -137,9 +135,9 @@
///////////////////////////////////////////////////////////////////////////////
#define CHECK_GT(A,B) do { \
DEBUG_ONLY( \
const auto __a = (A); \
const auto __b = (B); \
DEBUG_ONLY( \
const auto &__a = (A); \
const auto &__b = (B); \
\
if (__a <= __b) { \
_CHECK_PANIC ("expected greater than\n" \
@ -154,9 +152,9 @@
///////////////////////////////////////////////////////////////////////////////
#define CHECK_GE(A,B) do { \
DEBUG_ONLY( \
const auto __a = (A); \
const auto __b = (B); \
DEBUG_ONLY( \
const auto &__a = (A); \
const auto &__b = (B); \
\
if (__a < __b) { \
_CHECK_PANIC ("expected greater or equal\n" \
@ -171,10 +169,10 @@
///////////////////////////////////////////////////////////////////////////////
#define CHECK_LIMIT(V,L,H) do { \
DEBUG_ONLY( \
const auto __v = (V); \
const auto __l = (L); \
const auto __h = (H); \
DEBUG_ONLY( \
const auto &__v = (V); \
const auto &__l = (L); \
const auto &__h = (H); \
\
if (__v < __l || __v > __h) { \
_CHECK_PANIC ("expected limit\n" \
@ -190,9 +188,9 @@
///////////////////////////////////////////////////////////////////////////////
#define CHECK_NEQ(A,B) do { \
DEBUG_ONLY( \
const auto __a = (A); \
const auto __b = (B); \
DEBUG_ONLY( \
const auto &__a = (A); \
const auto &__b = (B); \
\
if (util::almost_equal (__a, __b)) { \
_CHECK_PANIC ("expected inequality\n" \
@ -207,8 +205,8 @@
///////////////////////////////////////////////////////////////////////////////
#define CHECK_ZERO(A) do { \
DEBUG_ONLY( \
const auto __a = (A); \
DEBUG_ONLY( \
const auto &__a = (A); \
\
if (!util::almost_zero (__a)) { \
_CHECK_PANIC ("expected zero\n" \
@ -221,8 +219,8 @@
///////////////////////////////////////////////////////////////////////////////
#define CHECK_NEZ(A) do { \
DEBUG_ONLY( \
const auto __a = (A); \
DEBUG_ONLY( \
const auto &__a = (A); \
if (util::exactly_zero (__a)) \
_CHECK_PANIC ("expected zero\n" \
"__a: %s is %!", \
@ -231,6 +229,21 @@
} while (0)
///////////////////////////////////////////////////////////////////////////////
#define CHECK_MOD(V,M) do { \
DEBUG_ONLY ( \
const auto &__check_mod_v = (V); \
const auto &__check_mod_m = (M); \
if (!util::exactly_zero (__check_mod_v % __check_mod_m)) \
_CHECK_PANIC ("expected zero modulus\n" \
"__v: %s is %!\n" \
"__m: %s is %!", \
#V, __check_mod_v, \
#M, __check_mod_m); \
); \
} while (0)
///////////////////////////////////////////////////////////////////////////////
#if defined(ENABLE_DEBUGGING)
#define CHECK_ENUM(C, ...) do { \
@ -253,7 +266,7 @@
///////////////////////////////////////////////////////////////////////////////
#define CHECK_THROWS(E,C) do { \
DEBUG_ONLY( \
DEBUG_ONLY( \
bool caught = false; \
\
try \
@ -269,7 +282,7 @@
///////////////////////////////////////////////////////////////////////////////
#define CHECK_NOTHROW(C) do { \
DEBUG_ONLY( \
DEBUG_ONLY( \
try { \
C; \
} catch (const std::exception &e) { \
@ -286,8 +299,9 @@
///////////////////////////////////////////////////////////////////////////////
constexpr void panic [[noreturn]] (const char*);
template <typename ...Args>
constexpr void panic [[noreturn]] (const char *fmt, const Args&...);
template <typename ...Args, size_t N>
constexpr
void panic [[noreturn]] (const char (&fmt)[N], const Args&...);
///////////////////////////////////////////////////////////////////////////////
@ -328,7 +342,14 @@ namespace util { namespace debug {
template <typename T>
bool valid (const T&);
struct validator {
static bool is_valid (const T&);
};
template <typename T>
bool is_valid (const T &t)
{ return validator<T>::is_valid (t); }
template <
@ -336,7 +357,7 @@ namespace util { namespace debug {
size_t S,
typename ...Args
>
struct validator {
struct validator<T<S,Args...>> {
static bool is_valid (const T<S,Args...>&);
};
@ -346,15 +367,15 @@ namespace util { namespace debug {
size_t S,
typename ...Args
>
bool valid (const T<S,Args...> &v)
{ return validator<T,S,Args...>::is_valid (v); }
bool is_valid (const T<S,Args...> &v)
{ return validator<T<S,Args...>>::is_valid (v); }
template <typename T>
void sanity (const T &t)
{
(void)t;
CHECK (valid (t));
CHECK (is_valid (t));
}
@ -365,13 +386,14 @@ namespace util { namespace debug {
void sanity (const T<Args...> &t)
{
(void)t;
CHECK (valid (t));
CHECK (is_valid (t));
}
} }
#include "./debug.ipp"
///////////////////////////////////////////////////////////////////////////////
// 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

View File

@ -28,9 +28,13 @@
namespace util { namespace debug { namespace detail {
void panic [[noreturn]] (const char *msg);
template <typename ...Args>
void panic [[noreturn]] (const char *msg, const Args& ...args)
{ panic (util::format::render (msg, args...).c_str ()); }
template <typename ...Args, size_t N>
constexpr
void panic [[noreturn]] (const char (&fmt)[N], const Args& ...args)
{
auto msg = util::format::render (fmt, args...);
panic (msg.c_str ());
}
void not_implemented [[noreturn]] (const char *msg);
void unreachable [[noreturn]] (const char *msg);
@ -92,12 +96,10 @@ constexpr void panic [[noreturn]] (const char *msg)
//-----------------------------------------------------------------------------
template <typename ...Args>
template <typename ...Args, size_t N>
constexpr
void
panic [[noreturn]] (const char *fmt, const Args& ...args)
panic [[noreturn]] (const char (&fmt)[N], const Args& ...args)
{
! fmt
? panic ("unreachable constexpr panic helper")
: util::debug::detail::panic (fmt, args...);
util::debug::detail::panic (fmt, args...);
}

View File

@ -21,6 +21,7 @@
#include "./except.hpp"
#include <windows.h>
#include <iostream>
///////////////////////////////////////////////////////////////////////////////

View File

@ -42,34 +42,6 @@ extent<S,T>::extent (vector<S,T> _v)
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
T
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>
T
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>
extent<S,T>
@ -216,7 +188,7 @@ extent_range<S,T>::iterator::operator!= (const iterator &rhs) const
///////////////////////////////////////////////////////////////////////////////
namespace util { namespace debug {
template <size_t S, typename T>
struct validator<extent,S,T> {
struct validator<extent<S,T>> {
static bool is_valid (const extent<S,T> &e)
{
return std::all_of (std::begin (e.data),
@ -226,11 +198,11 @@ namespace util { namespace debug {
};
} }
template bool util::debug::valid (const extent<2,float>&);
template bool util::debug::valid (const extent<2,double>&);
template bool util::debug::valid (const extent<2,uint16_t>&);
template bool util::debug::valid (const extent<2,uint32_t>&);
template bool util::debug::valid (const extent<2,uint64_t>&);
template bool util::debug::is_valid (const extent<2,float>&);
template bool util::debug::is_valid (const extent<2,double>&);
template bool util::debug::is_valid (const extent<2,uint16_t>&);
template bool util::debug::is_valid (const extent<2,uint32_t>&);
template bool util::debug::is_valid (const extent<2,uint64_t>&);
//-----------------------------------------------------------------------------

View File

@ -34,10 +34,11 @@ namespace util {
extent () = default;
explicit extent (vector<S,T>);
T area (void) const;
T diameter (void) const;
constexpr T area (void) const;
constexpr T diameter (void) const;
template <typename U = float>
constexpr
U aspect (void) const;
template <typename U>

View File

@ -24,9 +24,40 @@
#include <algorithm>
///////////////////////////////////////////////////////////////////////////////
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
{

View File

@ -20,7 +20,7 @@
#include "types/bits.hpp"
#include <cstdint>
#include <iostream>
#include <ostream>
namespace util {
template <typename T, unsigned I, unsigned E>

View File

@ -17,3 +17,59 @@
#include "format.hpp"
#include <utility>
namespace util { namespace format { namespace detail {
//-------------------------------------------------------------------------
std::ostream&
operator<< (std::ostream &os, specifier::repr r)
{
switch (r) {
case specifier::repr::FIXED: return os << "FIXED";
case specifier::repr::SCIENTIFIC: return os << "SCIENTIFIC";
case specifier::repr::AUTO: return os << "AUTO";
}
unreachable ();
}
//-------------------------------------------------------------------------
std::ostream&
operator<< (std::ostream &os, specifier::kind t)
{
switch (t) {
case specifier::kind::UNSIGNED: return os << "UNSIGNED";
case specifier::kind::SIGNED: return os << "SIGNED";
case specifier::kind::REAL: return os << "REAL";
case specifier::kind::STRING: return os << "STRING";
case specifier::kind::POINTER: return os << "POINTER";
case specifier::kind::CHARACTER: return os << "CHARACTER";
case specifier::kind::ESCAPE: return os << "ESCAPE";
case specifier::kind::OSTREAM: return os << "OSTREAM";
}
unreachable ();
}
//-------------------------------------------------------------------------
std::ostream&
operator<< (std::ostream &os, const specifier &s)
{
return os << "specifier {"
"alternate_form: " << s.alternate_form << ", "
"left_adjusted: " << s.left_adjusted << ", "
"thousands_grouping: " << s.thousands_grouping << ", "
"padding_char: '" << s.padding_char << "', "
"positive_char: '" << s.positive_char << "', "
"uppercase: " << s.uppercase << ", "
"base: " << s.base << ", "
"repr: " << s.r << ", "
"kind: " << s.k << ", "
"width: " << s.width << ", "
"precision: " << s.precision << ", "
"length: " << s.length <<
" }";
}
} } }

View File

@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2015-2016 Danny Robson <danny@nerdcruft.net>
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_FORMAT_HPP
@ -20,41 +20,56 @@
#include <stdexcept>
#include <string>
namespace util {
namespace format {
template <typename ...Args>
std::string
render (const std::string &fmt, Args&&...);
namespace util { namespace format {
//-------------------------------------------------------------------------
// render a format string using the provided values.
//
// we deliberately only take char[] formats so as to promote the use of
// only literal strings as format strings.
template <typename ...Args, size_t N>
std::string
render (const char (&fmt)[N], const Args&...);
class error : public std::runtime_error
{ using runtime_error::runtime_error; };
//-------------------------------------------------------------------------
class error : public std::runtime_error
{ using runtime_error::runtime_error; };
// value-specifier mismatch
class value_error : public error
{ using error::error; };
// value-specifier mismatch
class value_error : public error
{ using error::error; };
// malformed format specifier
class format_error : public error
{ using error::error; };
struct conversion_error : public error
{ using error::error; };
template <typename ValueT>
class invalid_specifier : public format_error {
public:
using value_type = ValueT;
struct length_error : public error
{ using error::error; };
invalid_specifier (char specifier);
// malformed format specifier
class syntax_error : public error
{ using error::error; };
char specifier (void) const;
template <typename ValueT>
class invalid_specifier : error {
public:
using value_type = ValueT;
private:
char m_specifier;
};
invalid_specifier (char specifier);
// missing format specifier
class missing_error : public error
{ using error::error; };
}
}
char specifier (void) const;
private:
char m_specifier;
};
// missing format specifier
class missing_error : public error
{
public:
missing_error ():
error ("missing argument for specifier")
{ ; }
};
} }
#include "format.ipp"

1099
format.ipp

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,8 @@
#include "./aabb.hpp"
#include "./iostream.hpp"
#include "../debug.hpp"
using util::geom::AABB;
@ -207,7 +209,7 @@ AABB<S,T>::operator== (const AABB<S,T> rhs) const
//-----------------------------------------------------------------------------
namespace util { namespace debug {
template <size_t S, typename T>
struct validator<AABB,S,T> {
struct validator<AABB<S,T>> {
static bool is_valid (const AABB<S,T> &b)
{
for (size_t i = 0; i < S; ++i)
@ -233,7 +235,7 @@ util::geom::operator<< (std::ostream &os, util::geom::AABB<S,T> b)
//-----------------------------------------------------------------------------
#define INSTANTIATE_S_T(S,T) \
namespace util { namespace geom { template struct AABB<S,T>; } } \
template bool util::debug::valid (const AABB<S,T>&); \
template bool util::debug::is_valid (const AABB<S,T>&); \
template std::ostream& util::geom::operator<< (std::ostream&, AABB<S,T>);
#define INSTANTIATE(T) \

View File

@ -65,9 +65,6 @@ namespace util { namespace geom {
typedef AABB<3,float> AABB3f;
typedef AABB<3,size_t> AABB3u;
typedef AABB<3,intmax_t> AABB3i;
template <size_t S, typename T>
std::ostream& operator<< (std::ostream&, AABB<S,T>);
} }
#include "aabb.ipp"

View File

@ -28,10 +28,10 @@ cylinder<S,T>::includes (util::point<S,T> p_) const
auto p_0 = p_ - p0;
auto l = dot (p10, p_0);
if (l < 0 || l > p10.magnitude2 ())
if (l < 0 || l > norm2 (p10))
return false;
auto d = dot (p10, p10) - l * l * p10.magnitude2 ();
auto d = dot (p10, p10) - l * l * norm2 (p10);
if (d > radius * radius)
return false;

View File

@ -19,9 +19,17 @@
#include "./fwd.hpp"
#include <iostream>
#include <ostream>
namespace util { namespace geom {
template <size_t S, typename T>
std::ostream&
operator<< (std::ostream&, AABB<S,T>);
template <size_t S, typename T>
std::ostream&
operator<< (std::ostream&, ray<S,T>);
template <size_t S, typename T>
std::ostream&
operator<< (std::ostream&, sphere<S,T>);

View File

@ -29,7 +29,7 @@ plane<S,T>::plane (point<S,T> _p,
p (_p),
n (_n)
{
CHECK_EQ (n.magnitude2 (), T{1});
CHECK (is_normalised (n));
}

View File

@ -14,9 +14,11 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "ray.hpp"
#include "./ray.hpp"
#include "./iostream.hpp"
#include "./ops.hpp"
#include "ops.hpp"
#include "../debug.hpp"
using util::geom::ray;
@ -29,7 +31,7 @@ ray<S,T>::ray (util::point<S,T> _origin,
origin (_origin),
direction (_direction)
{
CHECK (direction.is_normalised ());
CHECK (is_normalised (direction));
}
@ -41,7 +43,7 @@ ray<S,T>::make (util::point<S,T> origin,
{
return {
origin,
(target - origin).normalised ()
normalised (target - origin)
};
}

View File

@ -23,7 +23,7 @@
#include "../vector.hpp"
#include "../point.hpp"
#include <iostream>
#include <ostream>
namespace util { namespace geom {
template <size_t S, typename T>
@ -50,9 +50,6 @@ namespace util { namespace geom {
vector<S,T> direction;
};
template <size_t S, typename T>
std::ostream& operator<< (std::ostream&, ray<S,T>);
typedef ray<2,float> ray2f;
typedef ray<3,float> ray3f;
} }

View File

@ -24,6 +24,8 @@
#include <iomanip>
#include <sstream>
using util::guid;
///////////////////////////////////////////////////////////////////////////////
guid::guid (uint32_t _data1,

View File

@ -21,40 +21,45 @@
#include <ostream>
#include <istream>
class guid {
public:
enum type {
NCS_BACKWARD, // 0xx: Network Computing System backward compatibility
STANDARD, // 10x: Standard
COM_BACKWARD, // 110: Microsoft Component Object Model backward compatibility
RESERVED // 111: Reserved for future use
};
private:
guid (void);
///////////////////////////////////////////////////////////////////////////////
namespace util {
class guid {
public:
enum type {
NCS_BACKWARD, // 0xx: Network Computing System backward compatibility
STANDARD, // 10x: Standard
COM_BACKWARD, // 110: Microsoft Component Object Model backward compatibility
RESERVED // 111: Reserved for future use
};
public:
guid (uint32_t, uint16_t, uint16_t, uint8_t[8]);
explicit guid (const char *);
guid (const guid&);
private:
guid (void);
guid& operator= (const guid&);
public:
guid (uint32_t, uint16_t, uint16_t, uint8_t[8]);
explicit guid (const char *);
guid (const guid&);
static guid from_bytes (const uint8_t *bytes);
static guid from_string (const char *bytes);
guid& operator= (const guid&);
uint32_t data1;
uint16_t data2;
uint16_t data3;
uint8_t data4[8];
static guid from_bytes (const uint8_t *bytes);
static guid from_string (const char *bytes);
type get_type (void) const;
uint32_t data1;
uint16_t data2;
uint16_t data3;
uint8_t data4[8];
bool operator< (const guid&) const;
bool operator== (const guid&) const;
};
type get_type (void) const;
bool operator< (const guid&) const;
bool operator== (const guid&) const;
};
std::istream& operator>> (std::istream&, guid&);
std::ostream& operator<< (std::ostream&, const guid&);
}
std::istream& operator>> (std::istream&, guid&);
std::ostream& operator<< (std::ostream&, const guid&);
#endif

View File

@ -86,7 +86,7 @@ RIPEMD::update (const void *restrict _data, size_t len) noexcept
}
if (m_length >> sizeof (m_length) * 8 - 3 != 0)
throw std::length_error ("exceeded maximum message length");
panic ("exceeded maximum message length");
}

View File

@ -26,6 +26,7 @@
#include <cassert>
#include <cstdint>
#include <limits>
#include <ostream>
using util::hash::SHA1;
@ -36,8 +37,8 @@ std::ostream&
operator<< (std::ostream &os, SHA1::state_t t)
{
switch (t) {
case SHA1::READY: os << "READY"; return os;
case SHA1::FINISHED: os << "FINISHED"; return os;
case SHA1::READY: return os << "READY";
case SHA1::FINISHED: return os << "FINISHED";
}
unreachable ();

View File

@ -18,21 +18,21 @@
///////////////////////////////////////////////////////////////////////////////
constexpr char util::type_string<bool>::value[];
constexpr char util::type_name<bool>::value[];
constexpr char util::type_string< int8_t>::value[];
constexpr char util::type_string< int16_t>::value[];
constexpr char util::type_string< int32_t>::value[];
constexpr char util::type_string< int64_t>::value[];
constexpr char util::type_name< int8_t>::value[];
constexpr char util::type_name< int16_t>::value[];
constexpr char util::type_name< int32_t>::value[];
constexpr char util::type_name< int64_t>::value[];
constexpr char util::type_string< uint8_t>::value[];
constexpr char util::type_string<uint16_t>::value[];
constexpr char util::type_string<uint32_t>::value[];
constexpr char util::type_string<uint64_t>::value[];
constexpr char util::type_name< uint8_t>::value[];
constexpr char util::type_name<uint16_t>::value[];
constexpr char util::type_name<uint32_t>::value[];
constexpr char util::type_name<uint64_t>::value[];
constexpr char util::type_string<float>::value[];
constexpr char util::type_string<double>::value[];
constexpr char util::type_name<float>::value[];
constexpr char util::type_name<double>::value[];
constexpr char util::type_string<std::string>::value[];
constexpr char util::type_string<char*>::value[];
constexpr char util::type_string<const char*>::value[];
constexpr char util::type_name<std::string>::value[];
constexpr char util::type_name<char*>::value[];
constexpr char util::type_name<const char*>::value[];

View File

@ -26,43 +26,39 @@
#include <tuple>
namespace util {
template <
typename T
>
struct type_string {
// static const std::string value
};
template <typename T>
struct type_name;
template <> struct type_string<bool> { static constexpr const char value[] = "bool"; };
template <> struct type_name<bool> { static constexpr const char value[] = "bool"; };
template <> struct type_string<char> { static constexpr const char value[] = "char"; };
template <> struct type_string<void*> { static constexpr const char value[] = "void*"; };
template <> struct type_name<char> { static constexpr const char value[] = "char"; };
template <> struct type_name<void*> { static constexpr const char value[] = "void*"; };
template <> struct type_string< int8_t> { static constexpr const char value[] = "int8"; };
template <> struct type_string< int16_t> { static constexpr const char value[] = "int16"; };
template <> struct type_string< int32_t> { static constexpr const char value[] = "int32"; };
template <> struct type_string< int64_t> { static constexpr const char value[] = "int64"; };
template <> struct type_name< int8_t> { static constexpr const char value[] = "int8"; };
template <> struct type_name< int16_t> { static constexpr const char value[] = "int16"; };
template <> struct type_name< int32_t> { static constexpr const char value[] = "int32"; };
template <> struct type_name< int64_t> { static constexpr const char value[] = "int64"; };
template <> struct type_string< uint8_t> { static constexpr const char value[] = "uint8"; };
template <> struct type_string<uint16_t> { static constexpr const char value[] = "uint16"; };
template <> struct type_string<uint32_t> { static constexpr const char value[] = "uint32"; };
template <> struct type_string<uint64_t> { static constexpr const char value[] = "uint64"; };
template <> struct type_name< uint8_t> { static constexpr const char value[] = "uint8"; };
template <> struct type_name<uint16_t> { static constexpr const char value[] = "uint16"; };
template <> struct type_name<uint32_t> { static constexpr const char value[] = "uint32"; };
template <> struct type_name<uint64_t> { static constexpr const char value[] = "uint64"; };
template <> struct type_string<float > { static constexpr const char value[] = "float32"; };
template <> struct type_string<double > { static constexpr const char value[] = "float64"; };
template <> struct type_name<float > { static constexpr const char value[] = "float32"; };
template <> struct type_name<double > { static constexpr const char value[] = "float64"; };
template <> struct type_string<std::string> { static constexpr const char value[] = "string"; };
template <> struct type_string<char*> { static constexpr const char value[] = "cstring"; };
template <> struct type_string<const char*> { static constexpr const char value[] = "cstring"; };
template <> struct type_name<std::string> { static constexpr const char value[] = "string"; };
template <> struct type_name<char*> { static constexpr const char value[] = "cstring"; };
template <> struct type_name<const char*> { static constexpr const char value[] = "cstring"; };
template <typename T>
constexpr
const char* type_string_v = type_string<T>::value;
const char* type_name_v = type_name<T>::value;
template <typename T>
const char*
to_string (void)
{ return type_string_v<T>; }
{ return type_name_v<T>; }
///////////////////////////////////////////////////////////////////////////
@ -107,7 +103,7 @@ namespace util {
}; \
\
template <> \
struct type_string<::NS::E> { \
struct type_name<::NS::E> { \
static constexpr const char ns[] = #NS; \
static constexpr const char value[] = #E; \
}; \
@ -134,10 +130,10 @@ namespace util {
> util::enum_traits<::NS::E>::names; \
\
constexpr \
const char util::type_string<::NS::E>::ns[]; \
const char util::type_name<::NS::E>::ns[]; \
\
constexpr \
const char util::type_string<::NS::E>::value[]; \
const char util::type_name<::NS::E>::value[]; \
///------------------------------------------------------------------------

1
io.cpp
View File

@ -135,7 +135,6 @@ util::write (const posix::fd &out,
}
}
//////////////////////////////////////////////////////////////////////////////
int
indenter::overflow (int ch) {

View File

@ -27,24 +27,22 @@
using util::detail::posix::mapped_file;
//////////////////////////////////////////////////////////////////////////////
mapped_file::mapped_file (const char *_path, int fflags, int mflags)
mapped_file::mapped_file (const char *path, int fflags, int mflags):
mapped_file (util::posix::fd (path, fflags), mflags)
{ ; }
//-----------------------------------------------------------------------------
mapped_file::mapped_file (const ::util::posix::fd &src, int mflags)
{
try {
::util::posix::fd src (_path, fflags);
struct stat meta;
if (fstat (src, &meta) < 0)
throw errno_error ();
struct stat meta;
if (fstat (src, &meta) < 0)
throw errno_error ();
m_size = (size_t)meta.st_size;
m_data = (uint8_t *)mmap (NULL, m_size, mflags, MAP_SHARED, src, 0);
if (m_data == MAP_FAILED)
throw errno_error ();
} catch (const errno_error &e) {
// ignore zero length mapping error
if (e.code () == EINVAL && m_size == 0)
return;
}
m_size = (size_t)meta.st_size;
m_data = (uint8_t *)mmap (NULL, m_size, mflags, MAP_SHARED, src, 0);
if (m_data == MAP_FAILED)
throw errno_error ();
}

View File

@ -17,7 +17,7 @@
#ifndef __UTIL_IO_POSIX_HPP
#define __UTIL_IO_POSIX_HPP
#include "io.hpp"
#include "posix/fd.hpp"
#include "view.hpp"
@ -31,6 +31,7 @@ namespace util {
class mapped_file {
public:
mapped_file (const char *path, int fflags = O_RDONLY | O_BINARY, int mflags = PROT_READ);
mapped_file (const util::posix::fd&, int mflags = PROT_READ);
mapped_file (const mapped_file&) = delete;
mapped_file& operator= (const mapped_file&) = delete;

View File

@ -59,39 +59,21 @@ DWORD
mflags_to_protect (int mflags) {
DWORD res = 0;
if (mflags & util::detail::win32::PROT_READ) res |= PAGE_READONLY;
if (mflags & util::detail::win32::PROT_WRITE) res |= PAGE_READWRITE;
if (mflags & util::detail::win32::PROT_EXEC) res |= PAGE_EXECUTE;
if (mflags & PROT_READ) res |= PAGE_READONLY;
if (mflags & PROT_WRITE) res |= PAGE_READWRITE;
if (mflags & PROT_EXEC) res |= PAGE_EXECUTE;
return res;
}
///////////////////////////////////////////////////////////////////////////////
mapped_file::mapped_file (const boost::filesystem::path &path,
mapped_file::mapped_file (::util::win32::handle &&src,
int fflags,
int mflags):
m_file (std::forward<::util::win32::handle> (src)),
m_data (nullptr, UnmapViewOfFile)
{
// Cache the ASCII path to avoid memory scoping issues.
std::string path_str = path.string ();
// Get hold of the file we're attempting to map. Emulate some level of POXIS mmap.
m_file.reset (
CreateFile (
path_str.c_str (),
fflags_to_generic (fflags),
fflags == O_RDONLY ? FILE_SHARE_READ : 0,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
nullptr
)
);
if (m_file == INVALID_HANDLE_VALUE)
win32_error::throw_code ();
// I would rather perform checks on filesize after mapping, but mapping
// requires a check for empty files before we perform the mapping to
// detect errors it throws in that specific situation.
@ -135,6 +117,38 @@ mapped_file::mapped_file (const boost::filesystem::path &path,
}
//-----------------------------------------------------------------------------
mapped_file::mapped_file (const boost::filesystem::path &path,
int fflags,
int mflags):
mapped_file (
::util::win32::handle (
::CreateFile (
path.string ().c_str (),
fflags_to_generic (fflags),
fflags == O_RDONLY ? FILE_SHARE_READ : 0,
nullptr,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
nullptr
)
),
fflags,
mflags
)
{ ; }
//-----------------------------------------------------------------------------
mapped_file::mapped_file (const util::fd &src,
int fflags,
int mflags):
mapped_file (util::win32::handle (reinterpret_cast<HANDLE> (_get_osfhandle (src))),
fflags,
mflags)
{ };
///////////////////////////////////////////////////////////////////////////////
size_t
mapped_file::size (void) const

View File

@ -17,6 +17,7 @@
#ifndef __UTIL_IO_WIN32_HPP
#define __UTIL_IO_WIN32_HPP
#include "./io.hpp"
#include "./win32/handle.hpp"
#include "./view.hpp"
@ -27,20 +28,41 @@
#include <sys/types.h>
#include <fcntl.h>
///////////////////////////////////////////////////////////////////////////////
// compatibility definitions
enum : int {
PROT_NONE = 0,
PROT_READ = 1 << 0,
PROT_EXEC = 1 << 1,
PROT_WRITE = 1 << 2
};
//-----------------------------------------------------------------------------
enum : int {
MAP_SHARED,
MAP_PRIVATE,
MAP_ANONYMOUS
};
///////////////////////////////////////////////////////////////////////////////
// implementation definitions
namespace util {
namespace detail { namespace win32 {
enum {
PROT_NONE = 0,
PROT_READ = 1 << 0,
PROT_EXEC = 1 << 1,
PROT_WRITE = 1 << 2
};
class mapped_file {
public:
mapped_file (::util::win32::handle &&,
int fflags = O_RDONLY,
int mflags = PROT_READ);
mapped_file (const boost::filesystem::path &path,
int fflags = O_RDONLY,
int mflags = PROT_READ);
mapped_file (const util::fd&,
int fflag = O_RDONLY,
int mflags = PROT_READ);
mapped_file (const mapped_file&) = delete;
mapped_file& operator= (const mapped_file&) = delete;

128
ip.cpp.rl
View File

@ -1,128 +0,0 @@
/*
* This file is part of libgim.
*
* libgim is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* libgim is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with libgim. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2011-2016 Danny Robson <danny@nerdcruft.net>
*/
#include "ip.hpp"
#include "cast.hpp"
#include <stdexcept>
#include <iostream>
///////////////////////////////////////////////////////////////////////////////
const ipv4::ip ipv4::ip::LOOPBACK (127, 0, 0, 1);
const ipv4::ip ipv4::ip::ANY ( 0, 0, 0, 0);
//-----------------------------------------------------------------------------
const util::range<ipv4::port_t> ipv4::WELL_KNOWN_PORT ( 0, 1023),
ipv4::REGISTERED_PORT ( 1024, 49151),
ipv4::PRIVATE_PORT (49152, 65535);
///////////////////////////////////////////////////////////////////////////////
ipv4::ip::ip (uint32_t _integer):
m_integer (_integer)
{ ; }
//-----------------------------------------------------------------------------
ipv4::ip::ip (uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
m_octets[0] = a;
m_octets[1] = b;
m_octets[2] = c;
m_octets[3] = d;
}
///////////////////////////////////////////////////////////////////////////////
bool
ipv4::ip::operator== (const ipv4::ip &rhs) const
{
return m_integer == rhs.m_integer;
}
///////////////////////////////////////////////////////////////////////////////
// RFC 3986
%%{
machine ipv4;
octet = ( [0-9][0-9]? |
'1'[0-9][0-9] |
'2'[0-4][0-9] |
'25'[0-5])
> {
octetstart = fpc;
}
% {
octetend = fpc;
__octet = 0;
for (auto i = octetstart; i < octetend; ++i)
__octet = __octet * 10u + sign_cast<unsigned> (*i - '0');
};
ipv4 := (octet %{ __octets[0] = __octet; } '.'
octet %{ __octets[1] = __octet; } '.'
octet %{ __octets[2] = __octet; } '.'
octet %{ __octets[3] = __octet; })
> { __success = false; }
% { __success = true; }
$!{ __success = false; };
}%%
//-----------------------------------------------------------------------------
%%write data;
///////////////////////////////////////////////////////////////////////////////
ipv4::ip::ip (const std::string &data)
{
bool __success = true;
uint8_t __octets[4] = { 0, 0, 0, 0 };
const char *octetstart = data.data ();
const char *octetend = nullptr;
uint8_t __octet;
int cs = 0;
const char *p = data.data (),
*pe = p + data.size (),
*eof = pe;
%%write init;
%%write exec;
if (!__success)
throw ipv4::error ();
m_octets[0] = __octets[0];
m_octets[1] = __octets[1];
m_octets[2] = __octets[2];
m_octets[3] = __octets[3];
}
//-----------------------------------------------------------------------------
ipv4::ip
ipv4::ip::parse (const std::string &data)
{ return ipv4::ip (data); }

79
ip.hpp
View File

@ -1,79 +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>
*/
#ifndef __UTIL_IP_HPP
#define __UTIL_IP_HPP
#include "range.hpp"
#include <cstdint>
#include <string>
namespace ipv4 {
struct ip {
union {
uint8_t m_octets[4];
uint32_t m_integer;
};
explicit ip (const std::string &);
explicit ip (uint32_t i);
ip (uint8_t a, uint8_t b, uint8_t c, uint8_t d);
bool operator== (const ip &) const;
explicit operator uint32_t (void);
static ip parse (const std::string &);
static const ip LOOPBACK;
static const ip ANY;
};
typedef uint16_t port_t;
typedef uint32_t mask_t;
extern const util::range<port_t> WELL_KNOWN_PORT,
REGISTERED_PORT,
PRIVATE_PORT;
class error : public std::exception { };
}
namespace ipv6 {
struct ip {
uint32_t m_quads[4];
explicit ip (const std::string&) { ; }
};
typedef uint16_t port_t;
struct mask_t {
uint32_t m_quads[4];
explicit mask_t (uint32_t) { ; }
};
class error : public std::exception { };
}
#endif // __UTIL_IP_HPP

View File

@ -25,6 +25,7 @@
#include "preprocessor.hpp"
#include <deque>
#include <iostream>
//-----------------------------------------------------------------------------
%%{

View File

@ -18,7 +18,7 @@
#define __UTIL_JSON_FLAT_HPP
#include <boost/filesystem/path.hpp>
#include <iostream>
#include <ostream>
#include "../view.hpp"

View File

@ -32,6 +32,7 @@ struct length_error : public json::schema_error {
};
//-----------------------------------------------------------------------------
struct format_error : public json::schema_error {
using schema_error::schema_error;
};
@ -233,15 +234,47 @@ validate_number (T val, const json::tree::object &schema) {
if (exclusiveMax != schema.end () && exclusiveMax->second->as_boolean ()) {
switch (cmp.repr ()) {
case R::REAL: if (val >= T(cmp.real ())) throw json::schema_error ("exclusiveMax"); break;
case R::SINT: if (val >= T(cmp.uint ())) throw json::schema_error ("exclusiveMax"); break;
case R::UINT: if (val >= T(cmp.sint ())) throw json::schema_error ("exclusiveMax"); break;
case R::REAL:
if (T(val) >= cmp.real ())
throw json::schema_error ("exclusiveMax");
break;
case R::SINT:
if (json::tree::number::sint_t(std::numeric_limits<T>::max ()) >= cmp.sint () &&
val >= T(cmp.sint ()))
{
throw json::schema_error ("exclusiveMax");
}
break;
case R::UINT:
if (json::tree::number::uint_t(std::numeric_limits<T>::max ()) >= cmp.uint () &&
val >= T(cmp.uint ()))
{
throw json::schema_error ("exclusiveMax");
}
break;
}
} else {
switch (cmp.repr ()) {
case R::REAL: if (val > T(cmp.real ())) throw json::schema_error ("maximum"); break;
case R::SINT: if (val > T(cmp.sint ())) throw json::schema_error ("maximum"); break;
case R::UINT: if (val > T(cmp.uint ())) throw json::schema_error ("maximum"); break;
case R::REAL:
if (T(val) > cmp.real ())
throw json::schema_error ("maximum");
break;
case R::SINT:
if (json::tree::number::sint_t(std::numeric_limits<T>::max ()) >= cmp.sint () &&
val >= T(cmp.sint ()))
{
throw json::schema_error ("maximum");
}
break;
case R::UINT:
if (json::tree::number::uint_t(std::numeric_limits<T>::max ()) >= cmp.uint () &&
val >= T(cmp.uint ()))
{
throw json::schema_error ("maximum");
}
break;
}
}
} else {
@ -257,15 +290,47 @@ validate_number (T val, const json::tree::object &schema) {
if (exclusiveMin != schema.end () && exclusiveMin->second->as_boolean ()) {
switch (cmp.repr ()) {
case R::REAL: if (val <= T(cmp.real ())) throw json::schema_error ("exclusiveMin"); break;
case R::SINT: if (val <= T(cmp.sint ())) throw json::schema_error ("exclusiveMin"); break;
case R::UINT: if (val <= T(cmp.uint ())) throw json::schema_error ("exclusiveMin"); break;
case R::REAL:
if (T(val) < cmp.real ())
throw json::schema_error ("exclusiveMin");
break;
case R::SINT:
if (cmp.sint () > json::tree::number::sint_t(std::numeric_limits<T>::min ()) &&
val < T(cmp.sint ()))
{
throw json::schema_error ("exclusiveMin");
}
break;
case R::UINT:
if (cmp.uint () > json::tree::number::uint_t(std::numeric_limits<T>::min ()) &&
val < T(cmp.uint ()))
{
throw json::schema_error ("exclusiveMin");
}
break;
}
} else {
switch (cmp.repr ()) {
case R::REAL: if (val < T(cmp.real ())) throw json::schema_error ("minimum"); break;
case R::SINT: if (val < T(cmp.sint ())) throw json::schema_error ("minimum"); break;
case R::UINT: if (val < T(cmp.uint ())) throw json::schema_error ("minimum"); break;
case R::REAL:
if (T(val) <= cmp.real ())
throw json::schema_error ("minimum");
break;
case R::SINT:
if (cmp.sint () >= json::tree::number::sint_t(std::numeric_limits<T>::min ()) &&
val <= T(cmp.sint ()))
{
throw json::schema_error ("minimum");
}
break;
case R::UINT:
if (cmp.uint () >= json::tree::number::uint_t(std::numeric_limits<T>::min ()) &&
val <= T(cmp.uint ()))
{
throw json::schema_error ("minimum");
}
break;
}
}
} else {

View File

@ -30,7 +30,6 @@
#include <cstdlib>
#include <deque>
#include <iomanip>
#include <sstream>
#include <stdexcept>
#include <fcntl.h>
@ -870,14 +869,26 @@ json::tree::number::operator ==(const json::tree::number &rhs) const {
}
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
json::tree::number::real_t
json::tree::number::real (void) const
{
if (m_repr != REAL)
throw json::type_error ("number is not a real");
switch (repr ()) {
case REAL:
return m_value.r;
return m_value.r;
case UINT:
if (uint_t (real_t (m_value.u)) != m_value.u)
throw type_error ("number is not a real");
return m_value.u;
case SINT:
if (sint_t (real_t (m_value.s)) != m_value.s)
throw type_error ("number is not a real");
return m_value.s;
}
unreachable ();
}
@ -885,10 +896,22 @@ json::tree::number::real (void) const
json::tree::number::sint_t
json::tree::number::sint (void) const
{
if (m_repr != SINT)
throw json::type_error ("number is not a sint");
switch (repr ()) {
case SINT:
return m_value.s;
return m_value.s;
case REAL:
if (!::util::exactly_equal (real_t (sint_t (m_value.r)), m_value.r))
throw type_error ("number is not a sint");
return sint_t (m_value.r);
case UINT:
if (uint_t (sint_t (m_value.u)) != m_value.u)
throw type_error ("number is not a sint");
return m_value.s;
}
unreachable ();
}
@ -896,14 +919,26 @@ json::tree::number::sint (void) const
json::tree::number::uint_t
json::tree::number::uint (void) const
{
if (m_repr != UINT)
throw json::type_error ("number is not a uint");
switch (repr ()) {
case UINT:
return m_value.u;
return m_value.u;
case REAL:
if (!::util::exactly_equal (real_t (uint_t (m_value.r)), m_value.r))
throw type_error ("number is not a uint");
return uint_t (m_value.r);
case SINT:
if (sint_t (uint_t (m_value.s)) != m_value.s)
throw type_error ("number is not a uint");
return m_value.s;
}
unreachable ();
}
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
json::tree::number::operator json::tree::number::real_t (void) const
{
return real ();

View File

@ -23,7 +23,7 @@
#include "../iterator.hpp"
#include "../view.hpp"
#include <iostream>
#include <ostream>
#include <map>
#include <memory>
#include <string>

View File

@ -24,12 +24,12 @@
#include "cast.hpp"
#include <array>
#include <ctime>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <string>
#include <iomanip>
///////////////////////////////////////////////////////////////////////////////
static

View File

@ -20,7 +20,7 @@
#include "./nocopy.hpp"
#include "./preprocessor.hpp"
#include <iostream>
#include <ostream>
#include <string>
// Windows.h or one of its friends defines a macro 'ERROR'. Screw Microsoft.
@ -61,8 +61,8 @@ namespace util {
///////////////////////////////////////////////////////////////////////////
void log (level_t, const std::string &msg);
template <typename ...tail>
void log (level_t, const std::string &format, tail&& ..._tail);
template <typename ...Args, size_t N>
void log (level_t, const char (&fmt)[N], const Args&...);
//-------------------------------------------------------------------------

View File

@ -24,11 +24,11 @@
//-----------------------------------------------------------------------------
namespace util {
template <typename ...tail>
template <typename ...Args, size_t N>
void
log (level_t l, const std::string &format, tail&& ..._tail)
log (level_t l, const char (&fmt)[N], const Args& ...args)
{
log (l, format::render (format, std::forward<tail> (_tail)...));
log (l, format::render (fmt, args...));
}
}

View File

@ -1,67 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# For every FLAG1, FLAG2 it is checked whether the compiler works with the
# flag. If it does, the flag is added FLAGS-VARIABLE
#
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
# CFLAGS) is used. During the check the flag is always added to the
# current language's flags.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: This macro depends on the AX_APPEND_FLAG and
# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with
# AX_APPEND_LINK_FLAGS.
#
# LICENSE
#
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 5
AC_DEFUN([AX_APPEND_COMPILE_FLAGS],
[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
for flag in $1; do
AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4])
done
])dnl AX_APPEND_COMPILE_FLAGS

View File

@ -1,65 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_append_link_flags.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# For every FLAG1, FLAG2 it is checked whether the linker works with the
# flag. If it does, the flag is added FLAGS-VARIABLE
#
# If FLAGS-VARIABLE is not specified, the linker's flags (LDFLAGS) is
# used. During the check the flag is always added to the linker's flags.
#
# If EXTRA-FLAGS is defined, it is added to the linker's default flags
# when the check is done. The check is thus made with the flags: "LDFLAGS
# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
# issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: This macro depends on the AX_APPEND_FLAG and AX_CHECK_LINK_FLAG.
# Please keep this macro in sync with AX_APPEND_COMPILE_FLAGS.
#
# LICENSE
#
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 5
AC_DEFUN([AX_APPEND_LINK_FLAGS],
[AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
for flag in $1; do
AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3], [$4])
done
])dnl AX_APPEND_LINK_FLAGS

View File

@ -1,74 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# Check whether the given FLAG works with the current language's compiler
# or gives an error. (Warnings, however, are ignored)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 4
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
AS_VAR_IF(CACHEVAR,yes,
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_COMPILE_FLAGS

View File

@ -1,74 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# Check whether the given FLAG works with the linker or gives an error.
# (Warnings, however, are ignored)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# If EXTRA-FLAGS is defined, it is added to the linker's default flags
# when the check is done. The check is thus made with the flags: "LDFLAGS
# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
# issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_LINK_IFELSE.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 4
AC_DEFUN([AX_CHECK_LINK_FLAG],
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
ax_check_save_flags=$LDFLAGS
LDFLAGS="$LDFLAGS $4 $1"
AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
LDFLAGS=$ax_check_save_flags])
AS_VAR_IF(CACHEVAR,yes,
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_LINK_FLAGS

View File

@ -1,87 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_COMPILER_VENDOR
#
# DESCRIPTION
#
# Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm, sun,
# hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi, microsoft,
# watcom, etc. The vendor is returned in the cache variable
# $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++.
#
# LICENSE
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
# Copyright (c) 2008 Matteo Frigo
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 15
AC_DEFUN([AX_COMPILER_VENDOR],
[AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor,
dnl Please add if possible support to ax_compiler_version.m4
[# note: don't check for gcc first since some other compilers define __GNUC__
vendors="intel: __ICC,__ECC,__INTEL_COMPILER
ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__
pathscale: __PATHCC__,__PATHSCALE__
clang: __clang__
cray: _CRAYC
fujitsu: __FUJITSU
gnu: __GNUC__
sun: __SUNPRO_C,__SUNPRO_CC
hp: __HP_cc,__HP_aCC
dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER
borland: __BORLANDC__,__CODEGEARC__,__TURBOC__
comeau: __COMO__
kai: __KCC
lcc: __LCC__
sgi: __sgi,sgi
microsoft: _MSC_VER
metrowerks: __MWERKS__
watcom: __WATCOMC__
portland: __PGI
tcc: __TINYC__
unknown: UNKNOWN"
for ventest in $vendors; do
case $ventest in
*:) vendor=$ventest; continue ;;
*) vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" ;;
esac
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[
#if !($vencpp)
thisisanerror;
#endif
])], [break])
done
ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1`
])
])

View File

@ -1,485 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
#
# DESCRIPTION
#
# This macro figures out how to build C programs using POSIX threads. It
# sets the PTHREAD_LIBS output variable to the threads library and linker
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
# flags that are needed. (The user can also force certain compiler
# flags/libs to be tested by setting these environment variables.)
#
# Also sets PTHREAD_CC to any special C compiler that is needed for
# multi-threaded programs (defaults to the value of CC otherwise). (This
# is necessary on AIX to use the special cc_r compiler alias.)
#
# NOTE: You are assumed to not only compile your program with these flags,
# but also to link with them as well. For example, you might link with
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
# If you are only building threaded programs, you may wish to use these
# variables in your default LIBS, CFLAGS, and CC:
#
# LIBS="$PTHREAD_LIBS $LIBS"
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# CC="$PTHREAD_CC"
#
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
#
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
# PTHREAD_CFLAGS.
#
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
# is not found. If ACTION-IF-FOUND is not specified, the default action
# will define HAVE_PTHREAD.
#
# Please let the authors know if this macro fails on any platform, or if
# you have any other suggestions or comments. This macro was based on work
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
# grateful for the helpful feedback of numerous users.
#
# Updated for Autoconf 2.68 by Daniel Richard G.
#
# LICENSE
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 22
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_PROG_SED])
AC_LANG_PUSH([C])
ax_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on Tru64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
ax_pthread_save_CC="$CC"
ax_pthread_save_CFLAGS="$CFLAGS"
ax_pthread_save_LIBS="$LIBS"
AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
AC_MSG_RESULT([$ax_pthread_ok])
if test "x$ax_pthread_ok" = "xno"; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
CC="$ax_pthread_save_CC"
CFLAGS="$ax_pthread_save_CFLAGS"
LIBS="$ax_pthread_save_LIBS"
fi
# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
# (Note: HP C rejects this with "bad form for `-t' option")
# -pthreads: Solaris/gcc (Note: HP C also rejects)
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads and
# -D_REENTRANT too), HP C (must be checked before -lpthread, which
# is present but should not be used directly; and before -mthreads,
# because the compiler interprets this as "-mt" + "-hreads")
# -mthreads: Mingw32/gcc, Lynx/gcc
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
case $host_os in
freebsd*)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
ax_pthread_flags="-kthread lthread $ax_pthread_flags"
;;
hpux*)
# From the cc(1) man page: "[-mt] Sets various -D flags to enable
# multi-threading and also sets -lpthread."
ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
;;
openedition*)
# IBM z/OS requires a feature-test macro to be defined in order to
# enable POSIX threads at all, so give the user a hint if this is
# not set. (We don't define these ourselves, as they can affect
# other portions of the system API in unpredictable ways.)
AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
[
# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
AX_PTHREAD_ZOS_MISSING
# endif
],
[AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
;;
solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (N.B.: The stubs are missing
# pthread_cleanup_push, or rather a function called by this macro,
# so we could check for that, but who knows whether they'll stub
# that too in a future libc.) So we'll check first for the
# standard Solaris way of linking pthreads (-mt -lpthread).
ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
;;
esac
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
AS_IF([test "x$GCC" = "xyes"],
[ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"])
# The presence of a feature test macro requesting re-entrant function
# definitions is, on some systems, a strong hint that pthreads support is
# correctly enabled
case $host_os in
darwin* | hpux* | linux* | osf* | solaris*)
ax_pthread_check_macro="_REENTRANT"
;;
aix* | freebsd*)
ax_pthread_check_macro="_THREAD_SAFE"
;;
*)
ax_pthread_check_macro="--"
;;
esac
AS_IF([test "x$ax_pthread_check_macro" = "x--"],
[ax_pthread_check_cond=0],
[ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
# Are we compiling with Clang?
AC_CACHE_CHECK([whether $CC is Clang],
[ax_cv_PTHREAD_CLANG],
[ax_cv_PTHREAD_CLANG=no
# Note that Autoconf sets GCC=yes for Clang as well as GCC
if test "x$GCC" = "xyes"; then
AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
[/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
# if defined(__clang__) && defined(__llvm__)
AX_PTHREAD_CC_IS_CLANG
# endif
],
[ax_cv_PTHREAD_CLANG=yes])
fi
])
ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
ax_pthread_clang_warning=no
# Clang needs special handling, because older versions handle the -pthread
# option in a rather... idiosyncratic way
if test "x$ax_pthread_clang" = "xyes"; then
# Clang takes -pthread; it has never supported any other flag
# (Note 1: This will need to be revisited if a system that Clang
# supports has POSIX threads in a separate library. This tends not
# to be the way of modern systems, but it's conceivable.)
# (Note 2: On some systems, notably Darwin, -pthread is not needed
# to get POSIX threads support; the API is always present and
# active. We could reasonably leave PTHREAD_CFLAGS empty. But
# -pthread does define _REENTRANT, and while the Darwin headers
# ignore this macro, third-party headers might not.)
PTHREAD_CFLAGS="-pthread"
PTHREAD_LIBS=
ax_pthread_ok=yes
# However, older versions of Clang make a point of warning the user
# that, in an invocation where only linking and no compilation is
# taking place, the -pthread option has no effect ("argument unused
# during compilation"). They expect -pthread to be passed in only
# when source code is being compiled.
#
# Problem is, this is at odds with the way Automake and most other
# C build frameworks function, which is that the same flags used in
# compilation (CFLAGS) are also used in linking. Many systems
# supported by AX_PTHREAD require exactly this for POSIX threads
# support, and in fact it is often not straightforward to specify a
# flag that is used only in the compilation phase and not in
# linking. Such a scenario is extremely rare in practice.
#
# Even though use of the -pthread flag in linking would only print
# a warning, this can be a nuisance for well-run software projects
# that build with -Werror. So if the active version of Clang has
# this misfeature, we search for an option to squash it.
AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
# Create an alternate version of $ac_link that compiles and
# links in two steps (.c -> .o, .o -> exe) instead of one
# (.c -> exe), because the warning occurs only in the second
# step
ax_pthread_save_ac_link="$ac_link"
ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
ax_pthread_save_CFLAGS="$CFLAGS"
for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
ac_link="$ax_pthread_save_ac_link"
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
[ac_link="$ax_pthread_2step_ac_link"
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
[break])
])
done
ac_link="$ax_pthread_save_ac_link"
CFLAGS="$ax_pthread_save_CFLAGS"
AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
])
case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
no | unknown) ;;
*) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
esac
fi # $ax_pthread_clang = yes
if test "x$ax_pthread_ok" = "xno"; then
for ax_pthread_try_flag in $ax_pthread_flags; do
case $ax_pthread_try_flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-mt,pthread)
AC_MSG_CHECKING([whether pthreads work with -mt -lpthread])
PTHREAD_CFLAGS="-mt"
PTHREAD_LIBS="-lpthread"
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
PTHREAD_CFLAGS="$ax_pthread_try_flag"
;;
pthread-config)
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
PTHREAD_LIBS="-l$ax_pthread_try_flag"
;;
esac
ax_pthread_save_CFLAGS="$CFLAGS"
ax_pthread_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
# need a special flag -Kthread to make this header compile.)
# We check for pthread_join because it is in -lpthread on IRIX
# while pthread_create is in libc. We check for pthread_attr_init
# due to DEC craziness with -lpthreads. We check for
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
# if $ax_pthread_check_cond
# error "$ax_pthread_check_macro must be defined"
# endif
static void routine(void *a) { a = 0; }
static void *start_routine(void *a) { return a; }],
[pthread_t th; pthread_attr_t attr;
pthread_create(&th, 0, start_routine, 0);
pthread_join(th, 0);
pthread_attr_init(&attr);
pthread_cleanup_push(routine, 0);
pthread_cleanup_pop(0) /* ; */])],
[ax_pthread_ok=yes],
[])
CFLAGS="$ax_pthread_save_CFLAGS"
LIBS="$ax_pthread_save_LIBS"
AC_MSG_RESULT([$ax_pthread_ok])
AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Various other checks:
if test "x$ax_pthread_ok" = "xyes"; then
ax_pthread_save_CFLAGS="$CFLAGS"
ax_pthread_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
AC_CACHE_CHECK([for joinable pthread attribute],
[ax_cv_PTHREAD_JOINABLE_ATTR],
[ax_cv_PTHREAD_JOINABLE_ATTR=unknown
for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
[int attr = $ax_pthread_attr; return attr /* ; */])],
[ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
[])
done
])
AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
test "x$ax_pthread_joinable_attr_defined" != "xyes"],
[AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
[$ax_cv_PTHREAD_JOINABLE_ATTR],
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
ax_pthread_joinable_attr_defined=yes
])
AC_CACHE_CHECK([whether more special flags are required for pthreads],
[ax_cv_PTHREAD_SPECIAL_FLAGS],
[ax_cv_PTHREAD_SPECIAL_FLAGS=no
case $host_os in
solaris*)
ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
;;
esac
])
AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
test "x$ax_pthread_special_flags_added" != "xyes"],
[PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
ax_pthread_special_flags_added=yes])
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
[ax_cv_PTHREAD_PRIO_INHERIT],
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
[[int i = PTHREAD_PRIO_INHERIT;]])],
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
[ax_cv_PTHREAD_PRIO_INHERIT=no])
])
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
test "x$ax_pthread_prio_inherit_defined" != "xyes"],
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
ax_pthread_prio_inherit_defined=yes
])
CFLAGS="$ax_pthread_save_CFLAGS"
LIBS="$ax_pthread_save_LIBS"
# More AIX lossage: compile with *_r variant
if test "x$GCC" != "xyes"; then
case $host_os in
aix*)
AS_CASE(["x/$CC"],
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
[#handle absolute path differently from PATH based program lookup
AS_CASE(["x$CC"],
[x/*],
[AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
[AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
;;
esac
fi
fi
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
AC_SUBST([PTHREAD_LIBS])
AC_SUBST([PTHREAD_CFLAGS])
AC_SUBST([PTHREAD_CC])
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test "x$ax_pthread_ok" = "xyes"; then
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
:
else
ax_pthread_ok=no
$2
fi
AC_LANG_POP
])dnl AX_PTHREAD

View File

@ -1,37 +0,0 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_require_defined.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_REQUIRE_DEFINED(MACRO)
#
# DESCRIPTION
#
# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
# been defined and thus are available for use. This avoids random issues
# where a macro isn't expanded. Instead the configure script emits a
# non-fatal:
#
# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
#
# It's like AC_REQUIRE except it doesn't expand the required macro.
#
# Here's an example:
#
# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
#
# LICENSE
#
# Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 1
AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
])dnl AX_REQUIRE_DEFINED

2
m4/nc

@ -1 +1 @@
Subproject commit c5615481949aa6aaedd2c5d221ed17d2e05009b0
Subproject commit 006f69779160a490786399b1af6a7d1e251cd15c

View File

@ -57,26 +57,6 @@ template uint32_t util::log2 (uint32_t);
template uint64_t util::log2 (uint64_t);
///////////////////////////////////////////////////////////////////////////////
namespace util {
template <>
unsigned
digits (const uint32_t &v)
{
return (v >= 1000000000) ? 10 :
(v >= 100000000) ? 9 :
(v >= 10000000) ? 8 :
(v >= 1000000) ? 7 :
(v >= 100000) ? 6 :
(v >= 10000) ? 5 :
(v >= 1000) ? 4 :
(v >= 100) ? 3 :
(v >= 10) ? 2 :
1;
}
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
std::enable_if_t<

106
maths.hpp
View File

@ -17,13 +17,18 @@
#ifndef __MATHS_HPP
#define __MATHS_HPP
#include "./debug.hpp"
// DO NOT INCLUDE debug.hpp
// it triggers a circular dependency; debug -> format -> maths -> debug
// instead, just use cassert
#include "./types/traits.hpp"
#include "./float.hpp"
#include <cassert>
#include <cmath>
#include <cstdint>
#include <limits>
#include <numeric>
#include <type_traits>
#include <utility>
@ -281,9 +286,40 @@ namespace util {
//-----------------------------------------------------------------------------
template <typename T>
constexpr
unsigned
digits (const T& value);
digits10 (uint32_t v) noexcept
{
return (v >= 1000000000) ? 10 :
(v >= 100000000) ? 9 :
(v >= 10000000) ? 8 :
(v >= 1000000) ? 7 :
(v >= 100000) ? 6 :
(v >= 10000) ? 5 :
(v >= 1000) ? 4 :
(v >= 100) ? 3 :
(v >= 10) ? 2 :
1;
}
template <typename ValueT, typename BaseT>
constexpr
std::enable_if_t<
std::is_integral<ValueT>::value && std::is_unsigned<BaseT>::value,
unsigned
>
digits (ValueT value, BaseT base) noexcept
{
if (value < 0)
value *= -1;
unsigned tally = 1;
while (value /= base)
++tally;
return tally;
}
///----------------------------------------------------------------------------
@ -326,8 +362,8 @@ namespace util {
constexpr T
gcd (T a, T b)
{
CHECK_NEZ (a);
CHECK_NEZ (b);
assert (a);
assert (b);
while (a != b) {
if (a > b)
@ -349,6 +385,32 @@ namespace util {
}
///////////////////////////////////////////////////////////////////////////
// Modulus/etc
// namespaced wrapper for `man 3 fmod`
template <typename T>
constexpr
std::enable_if_t<
std::is_floating_point<T>::value, T
>
mod (T x, T y)
{
return std::fmod (x, y);
}
template <typename T>
constexpr
std::enable_if_t<
std::is_integral<T>::value, T
>
mod (T x, T y)
{
return x % y;
}
///////////////////////////////////////////////////////////////////////////////
// angles, trig
template <typename T>
@ -434,13 +496,16 @@ namespace util {
///////////////////////////////////////////////////////////////////////////////
// kahan summation for long floating point sequences
template <class InputIt>
typename std::iterator_traits<InputIt>::value_type
fsum (InputIt first, InputIt last)
template <class InputT>
std::enable_if_t<
std::is_floating_point<
typename std::iterator_traits<InputT>::value_type
>::value,
typename std::iterator_traits<InputT>::value_type
>
sum (InputT first, InputT last)
{
using T = typename std::iterator_traits<InputIt>::value_type;
static_assert (std::is_floating_point<T>::value,
"fsum only works for floating point types");
using T = typename std::iterator_traits<InputT>::value_type;
T sum = 0;
T c = 0;
@ -456,6 +521,21 @@ namespace util {
}
//-------------------------------------------------------------------------
template <class InputT>
std::enable_if_t<
std::is_integral<
typename std::iterator_traits<InputT>::value_type
>::value,
typename std::iterator_traits<InputT>::value_type
>
sum (InputT first, InputT last)
{
using T = typename std::iterator_traits<InputT>::value_type;
return std::accumulate (first, last, T{0});
}
///////////////////////////////////////////////////////////////////////////
/// Variadic minimum
template <typename T>
@ -506,7 +586,7 @@ namespace util {
constexpr T
limit (const T val, const U lo, const V hi)
{
CHECK_LE (lo, hi);
assert (lo <= hi);
return val > hi ? hi:
val < lo ? lo:
@ -520,7 +600,7 @@ namespace util {
T
smoothstep (T a, T b, T x)
{
CHECK_LE(a, b);
assert (a <= b);
x = limit ((x - a) / (b - a), T{0}, T{1});
return x * x * (3 - 2 * x);
}

View File

@ -16,8 +16,9 @@
#include "matrix.hpp"
#include "point.hpp"
#include "debug.hpp"
#include "iterator.hpp"
#include "point.hpp"
#include <cstring>
#include <cmath>
@ -129,7 +130,22 @@ util::matrix<S,T>::inverse (void) const
}
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
matrix<S,T>
util::transposed (const matrix<S,T> &m)
{
util::matrix<S,T> res;
for (size_t y = 0; y < S; ++y)
for (size_t x = 0; x < S; ++x)
res[y][x] = m[x][y];
return res;
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
matrix<S,T>
matrix<S,T>::operator* (const matrix<S,T> &rhs) const
@ -186,75 +202,6 @@ matrix<S,T>::operator* (const point<S,T> &rhs) const
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
matrix<S,T>
matrix<S,T>::operator* (T f) const
{
matrix<S,T> out;
for (size_t i = 0; i < S; ++i)
for (size_t j = 0; j < S; ++j)
out.values[i][j] = values[i][j] * f;
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
matrix<S,T>&
matrix<S,T>::operator*= (T f)
{
for (size_t i = 0; i < S; ++i)
for (size_t j = 0; j < S; ++j)
values[i][j] *= f;
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
util::matrix<S,T>
util::matrix<S,T>::operator/ (T t) const
{
auto out = *this;
for (auto &i: out.values)
for (auto &j: i)
j /= t;
return out;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
matrix<S,T>&
matrix<S,T>::operator/= (T s)
{
for (size_t r = 0; r < rows; ++r)
for (size_t c = 0; c < cols; ++c)
values[r][c] /= s;
return *this;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
bool
matrix<S,T>::operator== (const matrix<S,T> &rhs) const
{
for (size_t r = 0; r < rows; ++r)
for (size_t c = 0; c < cols; ++c)
if (!almost_equal (rhs.values[r][c], values[r][c]))
return false;
return true;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
bool
@ -330,35 +277,37 @@ matrix<S,T>::perspective (T fov, T aspect, range<T> Z)
template <size_t S, typename T>
matrix4<T>
matrix<S,T>::look_at (util::point<3,T> eye,
util::point<3,T> centre,
util::point<3,T> target,
util::vector<3,T> up)
{
const auto f = (centre - eye).normalise ();
const auto s = cross (f, up).normalise ();
const auto u = cross (s, f);
auto forward = normalised (eye.to (target));
auto side = normalised (cross (forward, up));
up = cross (side, forward);
return { {
{ s.x, s.y, s.z, -dot (s, eye) },
{ u.x, u.y, u.z, -dot (u, eye) },
{ -f.x, -f.y, -f.z, dot (f, eye) },
{ 0, 0, 0, 1 },
} };
auto rot = util::matrix4<T> {{
{ side[0], up[0], -forward[0], 0 },
{ side[1], up[1], -forward[1], 0 },
{ side[2], up[2], -forward[2], 0 },
{ 0, 0, 0, 1 }
}};
return util::matrix4<T>::translation (-eye.template as<vector> ()) * rot;
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
matrix4<T>
matrix<S,T>::translate (util::vector<2,T> v)
matrix<S,T>::translation (util::vector<2,T> v)
{
return translate ({v.x, v.y, 0});
return translation ({v.x, v.y, 0});
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
matrix4<T>
matrix<S,T>::translate (util::vector<3,T> v)
matrix<S,T>::translation (util::vector<3,T> v)
{
return { {
{ 1.f, 0.f, 0.f, v.x },
@ -394,9 +343,9 @@ matrix<S,T>::scale (util::vector<3,T> v)
//-----------------------------------------------------------------------------
template <size_t S, typename T>
matrix4<T>
matrix<S,T>::rotate (T angle, util::vector<3,T> about)
matrix<S,T>::rotation (T angle, util::vector<3,T> about)
{
about.normalise ();
CHECK (is_normalised (about));
T c = std::cos (angle);
T s = std::sin (angle);
@ -434,45 +383,64 @@ matrix<S,T>::ZEROES { 0 };
//-----------------------------------------------------------------------------
namespace util {
template struct matrix<2,float>;
template struct matrix<2,double>;
template struct util::matrix<2,float>;
template struct util::matrix<2,double>;
template struct matrix<3,float>;
template struct matrix<3,double>;
template struct util::matrix<3,float>;
template struct util::matrix<3,double>;
template struct matrix<4,float>;
template struct matrix<4,double>;
template struct util::matrix<4,float>;
template struct util::matrix<4,double>;
///////////////////////////////////////////////////////////////////////////////
// Uses the algorithm from:
// "Extracting Euler Angles from a Rotation Matrix" by
// Mike Day, Insomniac Games.
template <size_t S, typename T>
util::vector<3,T>
util::to_euler (const matrix<S,T> &m)
{
static_assert (S == 3 || S == 4, "only defined for 3d affine transforms");
const auto theta0 = std::atan2 (m[2][1], m[2][2]);
const auto c1 = std::hypot (m[0][0], m[1][0]);
const auto theta1 = std::atan2 (-m[2][0], c1);
const auto s0 = std::sin(theta0);
const auto c0 = std::cos(theta0);
const auto theta2 = std::atan2(
s0 * m[0][2] - c0 * m[0][1],
c0 * m[1][1] - s0 * m[1][2]
);
return { theta0, theta1, theta2 };
}
//-----------------------------------------------------------------------------
namespace util {
template <size_t S, typename T>
std::ostream&
operator<< (std::ostream &os, const matrix<S,T> &m)
{
os << "{ {" << m.values[0][0] << ", "
<< m.values[0][1] << ", "
<< m.values[0][2] << ", "
<< m.values[0][3] << "}, "
<< "{" << m.values[1][0] << ", "
<< m.values[1][1] << ", "
<< m.values[1][2] << ", "
<< m.values[1][3] << "}, "
<< "{" << m.values[2][0] << ", "
<< m.values[2][1] << ", "
<< m.values[2][2] << ", "
<< m.values[2][3] << "}, "
<< "{" << m.values[3][0] << ", "
<< m.values[3][1] << ", "
<< m.values[3][2] << ", "
<< m.values[3][3] << "} }";
template util::vector<3,float> util::to_euler (const matrix<3,float>&);
template util::vector<3,float> util::to_euler (const matrix<4,float>&);
return os;
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
std::ostream&
util::operator<< (std::ostream &os, const matrix<S,T> &m)
{
os << "{ ";
for (size_t i = 0; i < S; ++i) {
os << "{ ";
std::copy (m[i], m[i]+S, util::infix_iterator<float> (os, ", "));
os << ((i == S - 1) ? " }" : " }, ");
}
return os << " }";
}
//-----------------------------------------------------------------------------
template std::ostream& util::operator<< (std::ostream&, const matrix<4,float>&);
template std::ostream& util::operator<< (std::ostream&, const matrix<4,double>&);

View File

@ -27,12 +27,22 @@ namespace util {
struct matrix {
T values[S][S];
static const size_t rows = S;
static const size_t cols = S;
static constexpr size_t rows = S;
static constexpr size_t cols = S;
// index operators return a pointer into the data array so that
// multidimensional array syntax can be used transparently on this
// type.
T* operator[] (size_t);
const T* operator[] (size_t) const;
const T* begin (void) const;
const T* end (void) const;
T* begin (void);
T* end (void);
const T* cbegin (void) const;
const T* cend (void) const;
matrix& transpose (void);
matrix transposed (void) const;
@ -43,21 +53,12 @@ namespace util {
matrix inverse_affine (void) const;
matrix& invert_affine (void);
T det (void) const;
matrix operator* (const matrix&) const;
matrix& operator*=(const matrix&);
vector<S,T> operator* (const vector<S,T>&) const;
point<S,T> operator* (const point<S,T> &) const;
matrix operator* (T) const;
matrix& operator*= (T);
matrix operator/ (T) const;
matrix& operator/= (T);
bool operator== (const matrix&) const;
bool is_affine (void) const;
template <typename U>
@ -67,14 +68,14 @@ namespace util {
static matrix<4,T> ortho (T left, T right, T bottom, T top, T near, T far);
static matrix<4,T> ortho2D (T left, T right, T bottom, T top);
static matrix<4,T> perspective (T fov, T aspect, range<T> Z);
static matrix<4,T> look_at (point<3,T> eye, point<3,T> centre, vector<3,T> up);
static matrix<4,T> look_at (point<3,T> eye, point<3,T> target, vector<3,T> up);
// Affine matrices
static matrix<4,T> translate (util::vector<2,T>);
static matrix<4,T> translate (util::vector<3,T>);
static matrix<4,T> scale (util::vector<3,T>);
static matrix<4,T> scale (T);
static matrix<4,T> rotate (T angle, util::vector<3,T> about);
static matrix<4,T> translation (util::vector<2,T>);
static matrix<4,T> translation (util::vector<3,T>);
static matrix<4,T> scale (util::vector<3,T>);
static matrix<4,T> scale (T);
static matrix<4,T> rotation (T angle, util::vector<3,T> about);
// Constant matrices
static const matrix IDENTITY;
@ -82,13 +83,87 @@ namespace util {
};
///////////////////////////////////////////////////////////////////////////
// Convert an affine rotation matrix to euler angles.
//
// Results are undefined if the matrix is not purely a rotation matrix,
// or if the dimension is not 3x3 or 4x4.
template <size_t S, typename T>
T determinant (const matrix<S,T>&);
vector<3,T>
to_euler (const matrix<S,T>&);
///////////////////////////////////////////////////////////////////////////
// logical operations
template <size_t S, typename T>
constexpr
bool
operator== (const matrix<S,T>&, const matrix<S,T>&);
template <size_t S, typename T>
constexpr
bool
operator!= (const matrix<S,T>&, const matrix<S,T>&);
///////////////////////////////////////////////////////////////////////////
// element operations
template <size_t S, typename T>
constexpr
matrix<S,T>
operator+ (const matrix<S,T>&, const matrix<S,T>&);
template <size_t S, typename T>
constexpr
matrix<S,T>
operator- (const matrix<S,T>&, const matrix<S,T>&);
///////////////////////////////////////////////////////////////////////////
// scalar operations
template <size_t S, typename T> constexpr matrix<S,T> operator* (const matrix<S,T>&, T);
template <size_t S, typename T> constexpr matrix<S,T> operator/ (const matrix<S,T>&, T);
template <size_t S, typename T> constexpr matrix<S,T> operator+ (const matrix<S,T>&, T);
template <size_t S, typename T> constexpr matrix<S,T> operator- (const matrix<S,T>&, T);
template <size_t S, typename T> constexpr matrix<S,T> operator* (T, const matrix<S,T>&);
template <size_t S, typename T> constexpr matrix<S,T> operator/ (T, const matrix<S,T>&);
template <size_t S, typename T> constexpr matrix<S,T> operator+ (T, const matrix<S,T>&);
template <size_t S, typename T> constexpr matrix<S,T> operator- (T, const matrix<S,T>&);
template <size_t S, typename T> constexpr matrix<S,T>& operator*= (matrix<S,T>&, T);
template <size_t S, typename T> constexpr matrix<S,T>& operator/= (matrix<S,T>&, T);
template <size_t S, typename T> constexpr matrix<S,T>& operator+= (matrix<S,T>&, T);
template <size_t S, typename T> constexpr matrix<S,T>& operator-= (matrix<S,T>&, T);
///////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
T
determinant (const matrix<S,T>&);
template <size_t S, typename T>
matrix<S,T>
inverse (const matrix<S,T>&);
template <size_t S, typename T>
matrix<S,T>
transposed (const matrix<S,T>&);
///////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
matrix<S,T>
abs (const matrix<S,T>&);
template <size_t S, typename T>
constexpr
T
sum (const matrix<S,T>&);
///////////////////////////////////////////////////////////////////////////
template <typename T> using matrix3 = matrix<3,T>;
template <typename T> using matrix4 = matrix<4,T>;
@ -104,6 +179,8 @@ namespace util {
typedef matrix<4,float> matrix4f;
typedef matrix<4,double> matrix4d;
///////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
std::ostream& operator<< (std::ostream&, const matrix<S,T>&);
}

View File

@ -39,25 +39,59 @@ util::matrix<S,T>::operator[] (size_t idx) const
return this->values[idx];
}
///////////////////////////////////////////////////////////////////////////////
//template <size_t S, typename T>
//vector<3,T>
//matrix<S,T>::operator* (vector<3,T> v) const
//{
// return (
// *this * v.template homog<S> ()
// ).template redim<3> ();
//}
//
//
////-----------------------------------------------------------------------------
//template <size_t S, typename T>
//point<3,T>
//matrix<S,T>::operator* (point<3,T> p) const
//{
// return (*this * p.template homog<S> ()).template redim<3> ();
//}
//
//-----------------------------------------------------------------------------
template <size_t S, typename T>
const T*
util::matrix<S,T>::begin (void) const
{
return &(*this)[0][0];
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
const T*
util::matrix<S,T>::end (void) const
{
return &(*this)[S][0];
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
const T*
util::matrix<S,T>::cbegin (void) const
{
return begin ();
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
const T*
util::matrix<S,T>::cend (void) const
{
return end ();
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
T*
util::matrix<S,T>::begin (void)
{
return &(*this)[0][0];
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
T*
util::matrix<S,T>::end (void)
{
return &(*this)[S][0];
}
///////////////////////////////////////////////////////////////////////////////
@ -67,56 +101,124 @@ util::matrix<S,U>
util::matrix<S,T>::cast (void) const
{
util::matrix<S,U> out;
for (size_t i = 0; i < rows; ++i)
for (size_t j = 0; j < cols; ++j)
out.values[i][j] = values[i][j];
std::copy (cbegin (), cend (), std::begin (out));
return out;
}
/////////////////////////////////////////////////////////////////////////////////
//template <size_t S, typename T>
//T
//util::matrix<S,T>::determinant (void) const
//{
// return util::determinant (*this);
//}
//
//
////-----------------------------------------------------------------------------
//template <size_t S, typename T>
//util::matrix<S,T>
//util::matrix<S,T>::inverse (void) const
//{
// return util::inverse (*this);
//}
///////////////////////////////////////////////////////////////////////////////
#define MATRIX_ELEMENT_OP(OP) \
template <size_t S, typename T> \
constexpr \
util::matrix<S,T> \
util::operator OP ( \
const util::matrix<S,T> &a, \
const util::matrix<S,T> &b) \
{ \
util::matrix<S,T> res {}; \
\
for (size_t i = 0; i < a.rows; ++i) \
for (size_t j = 0; j < a.cols; ++j) \
res[i][j] = a[i][j] OP b[i][j]; \
\
return res; \
}
MATRIX_ELEMENT_OP(-)
MATRIX_ELEMENT_OP(+)
#undef MATRIX_ELEMENT_OP
///////////////////////////////////////////////////////////////////////////////
//template <size_t S, typename T>
//util::matrix<S,T>
//util::matrix<S,T>::operator/ (T t) const
//{
// auto out = *this;
//
// for (auto &i: out.values)
// for (auto &j: i)
// j /= t;
//
// return out;
//}
//
//
/////////////////////////////////////////////////////////////////////////////////
//template <size_t S, typename T>
//bool
//util::matrix<S,T>::operator== (const matrix<S,T> &m) const
//{
// for (size_t i = 0; i < S; ++i)
// for (size_t j = 0; j < S; ++j)
// if (!exactly_equal (values[i][j], m[i][j]))
// return false;
// return true;
//}
#define MATRIX_SCALAR_OP(OP) \
template <size_t S, typename T> \
constexpr \
util::matrix<S,T> \
util::operator OP (const util::matrix<S,T> &m, const T t) \
{ \
util::matrix<S,T> res {}; \
\
std::transform ( \
std::cbegin (m), \
std::cend (m), \
std::begin (res), \
[&t] (auto x) { return x OP t; } \
); \
\
return res; \
} \
\
\
template <size_t S, typename T> \
constexpr \
util::matrix<S,T> \
util::operator OP (const T t, const util::matrix<S,T> &m) \
{ \
return m OP t; \
} \
\
\
template <size_t S, typename T> \
constexpr \
util::matrix<S,T>& \
util::operator OP##= (util::matrix<S,T> &m, T t) \
{ \
std::transform ( \
std::cbegin (m), \
std::cend (m), \
std::begin (m), \
[&t] (auto x) { return x OP t; } \
); \
\
return m; \
}
MATRIX_SCALAR_OP(*)
MATRIX_SCALAR_OP(/)
MATRIX_SCALAR_OP(+)
MATRIX_SCALAR_OP(-)
#undef MATRIX_SCALAR_OP
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
constexpr
bool
util::operator== (const matrix<S,T> &a, const matrix<S,T> &b)
{
return std::equal (std::cbegin (a), std::cend (a), std::cbegin (b));
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
constexpr
bool
util::operator!= (const matrix<S,T> &a, const matrix<S,T> &b)
{
return !(a == b);
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
util::matrix<S,T>
util::abs (const util::matrix<S,T> &src)
{
util::matrix<S,T> dst;
std::transform (std::cbegin (src), std::cend (src), std::begin (dst), util::abs<T>);
return dst;
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
constexpr
T
util::sum (const util::matrix<S,T> &src)
{
return sum (std::cbegin (src), std::cend (src));
}

View File

@ -17,9 +17,10 @@
#include "./circular.hpp"
#include "../system.hpp"
#include "../../debug.hpp"
#include "../../except.hpp"
#include "../../raii.hpp"
#include "../../maths.hpp"
#include "../../raii.hpp"
#include "../../random.hpp"
#include <cstring>

View File

@ -1,167 +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 Danny Robson <danny@nerdcruft.net>
*/
#include "address.hpp"
#include "except.hpp"
#include "../debug.hpp"
#include "../endian.hpp"
#include "../types.hpp"
#include "../raii.hpp"
#ifdef __WIN32
#else
#include <netdb.h>
#include <arpa/inet.h>
#endif
using net::address;
///////////////////////////////////////////////////////////////////////////////
#ifdef __WIN32
const char* inet_ntop(int af, const void* src, char* dst, int size){
struct sockaddr_in srcaddr;
memset(&srcaddr, 0, sizeof(struct sockaddr_in));
memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));
srcaddr.sin_family = af;
if (WSAAddressToString ((struct sockaddr*) &srcaddr, sizeof (struct sockaddr_in), 0, dst, (LPDWORD) &size) != 0)
net::error::throw_code ();
return dst;
}
#endif
///////////////////////////////////////////////////////////////////////////////
template <net::domain D>
typename address<D>::port_type
address<D>::port (void) const
{ return m_port; }
//-----------------------------------------------------------------------------
template <net::domain D>
void
address<D>::set_port (const port_type &_port)
{ m_port = _port; }
//-----------------------------------------------------------------------------
template <net::domain D>
typename address<D>::ip_type
address<D>::resolve (const std::string &str) {
addrinfo hint;
memset (&hint, 0, sizeof (hint));
hint.ai_family = static_cast<int> (D);
addrinfo* resolved;
int err = getaddrinfo (str.c_str (), nullptr, nullptr, &resolved);
if (err)
net::error::throw_code ();
auto deletor = [] (addrinfo *a) { freeaddrinfo (a); };
std::unique_ptr<addrinfo, decltype(deletor)> raii(resolved, deletor);
return ip_type (reinterpret_cast<sockaddr_type*> (resolved->ai_addr)->sin_addr.s_addr);
}
///////////////////////////////////////////////////////////////////////////////
namespace net {
template <>
address<net::domain::INET>::address (const sockaddr_type &addr):
m_ip (addr.sin_addr.s_addr),
m_mask (0),
m_port (ntoh (addr.sin_port))
{
CHECK (addr.sin_family == (int)net::domain::INET);
}
template <net::domain D>
address<D>::address (const std::string &_addr,
port_type _port):
m_ip (resolve (_addr)),
m_mask ( 0),
m_port (_port)
{ ; }
template <>
address<net::domain::INET>::sockaddr_type
address<net::domain::INET>::to_sockaddr (void) const {
sockaddr_type addr;
addr.sin_family = (int)net::domain::INET;
addr.sin_port = hton (m_port);
addr.sin_addr.s_addr = m_ip.m_integer;
return addr;
}
template <>
std::string
address<net::domain::INET>::to_string (void) const {
char dest[INET_ADDRSTRLEN + 1];
sockaddr_type addr = to_sockaddr ();
if (NULL == inet_ntop ((int)net::domain::INET, &addr.sin_addr, dest, sizeof (dest)))
net::error::throw_code ();
return dest;
}
template <>
bool
address<net::domain::INET>::operator ==(const address<net::domain::INET> &rhs) {
return m_ip == rhs.m_ip &&
m_mask == rhs.m_mask &&
m_port == rhs.m_port;
}
}
///////////////////////////////////////////////////////////////////////////////
std::ostream&
net::operator<< (std::ostream &os, const address<net::domain::INET> &addr) {
os << addr.to_string () << ":" << addr.port ();
return os;
}
///////////////////////////////////////////////////////////////////////////////
template <> const address<net::domain::INET>
address<net::domain::INET>::LOOPBACK ("127.0.0.1", 0);
template <> const address<net::domain::INET>
address<net::domain::INET>::ANY ("0.0.0.0", 0);
namespace net {
template class address<net::domain::INET>;
}
//-----------------------------------------------------------------------------
//template <> const address<net::domain::INET6>
//address<net::domain::INET6>::LOOPBACK ("::1", 0);
//
//template <> const address<net::domain::INET6>
//address<net::domain::INET6>::ANY ("::0", 0);
//
//template class address<net::domain::INET6>;

View File

@ -1,97 +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 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __NET_ADDRESS_HPP
#define __NET_ADDRESS_HPP
#include "types.hpp"
#include "../ip.hpp"
#if defined(HAVE_WINSOCK2_H)
#include "ws2tcpip.h"
#endif
#include <iostream>
#include <string>
//-----------------------------------------------------------------------------
namespace net {
/// Supporting types used for defining addresses in various domains
template <domain D>
struct address_types;
template <>
struct address_types <domain::INET> {
typedef ipv4::ip ip;
typedef ipv4::mask_t mask_t;
typedef ipv4::port_t port_t;
typedef sockaddr_in sockaddr;
};
template <>
struct address_types <domain::INET6> {
typedef ipv6::ip ip;
typedef ipv6::mask_t mask_t;
typedef ipv6::port_t port_t;
typedef sockaddr_in6 sockaddr;
};
/// A full endpoint specification for a domain. Must be usable for bind/listen and send/recv.
template <domain D>
class address {
public:
typedef typename address_types<D>::ip ip_type;
typedef typename address_types<D>::mask_t mask_type;
typedef typename address_types<D>::port_t port_type;
typedef typename address_types<D>::sockaddr sockaddr_type;
protected:
ip_type m_ip;
mask_type m_mask;
port_type m_port;
public:
static const address<D> LOOPBACK;
static const address<D> ANY;
explicit address (const sockaddr_type &);
address (const std::string &address, port_type);
port_type port (void) const;
void set_port (const port_type &);
ip_type ip (void) const { return m_ip; }
sockaddr_type to_sockaddr (void) const;
std::string to_string (void) const;
static ip_type resolve (const std::string &);
bool operator ==(const address<D> &rhs);
};
std::ostream&
operator<< (std::ostream &os, const net::address<net::domain::INET> &addr);
}
#endif // __NET_ADDRESS_HPP

View File

@ -1,122 +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 Danny Robson <danny@nerdcruft.net>
*/
#include "except.hpp"
#include "../debug.hpp"
#include "../cast.hpp"
using net::error;
///////////////////////////////////////////////////////////////////////////////
net::error::error (const std::string &_what):
runtime_error (_what)
{ ; }
//-----------------------------------------------------------------------------
net::error::error (int _code):
runtime_error (strerror (_code))
{ CHECK (_code != 0); }
///////////////////////////////////////////////////////////////////////////////
std::string
net::error::code_to_string (int code) {
#ifdef __WIN32
char message[256];
// It should be fine to signcast the code here as Windows guarantees all
// error messages are positive but appears to use int for compatibility
DWORD output = FormatMessage (0, NULL, sign_cast<unsigned> (code), 0, message, sizeof (message), NULL);
CHECK_NEQ (output, 0);
return std::string (message);
#else
return strerror (code);
#endif
}
///////////////////////////////////////////////////////////////////////////////
void
net::error::throw_code (int code) {
#ifdef __WIN32
throw net::error (code);
#else
CHECK (code != 0);
switch (code) {
#define ERROR_CODE(c) \
case c: \
throw net::error_code<c> (); \
break;
ERROR_CODE(ECONNREFUSED);
ERROR_CODE(ECONNRESET);
ERROR_CODE(EINVAL);
ERROR_CODE(ENOTCONN);
default:
unreachable ();
#undef ERROR_CODE
}
#endif
}
void
net::error::throw_code (void)
{ throw_code (last_code ()); }
//-----------------------------------------------------------------------------
void
net::error::try_code (int err) {
if (__builtin_expect (err != 0, false))
throw_code (err);
}
void
net::error::try_code (void)
{ try_code (last_code ()); }
//-----------------------------------------------------------------------------
int
net::error::last_code (void) {
#ifdef __WIN32
return WSAGetLastError ();
#else
return errno;
#endif
}
//-----------------------------------------------------------------------------
template <int CODE>
net::error_code<CODE>::error_code (void):
net::error (CODE)
{ ; }
template <int CODE>
int
net::error_code<CODE>::code (void) const
{ return CODE; }

View File

@ -1,74 +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 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __NET_EXCEPT_HPP
#define __NET_EXCEPT_HPP
#if defined(HAVE_WINSOCK2_H)
#include <winsock2.h>
#else
#include <cerrno>
#include <cstring>
#endif
#include <string>
#include <stdexcept>
//-----------------------------------------------------------------------------
namespace net {
class error : public std::runtime_error {
protected:
explicit error (const std::string &);
explicit error (int code);
static std::string
code_to_string (int code);
public:
/// Throw an error corresponding the a given code. Code must be a valid error code,
/// not success otherwise the application will (at best) abort.
static void
throw_code [[noreturn]] (int code);
/// Throw an error corresponding to the most recent error condition. This will check
/// the current error condition in a platform agnostic manner, and pass on to
/// throw_code(int). This should be used whenever an error has been detected, rather
/// than the more normal try_code(errno) due to Windows error reporting quirks.
static void
throw_code [[noreturn]] (void);
static void
try_code (int code);
static void
try_code (void);
static int
last_code (void);
};
template <int CODE>
class error_code : public error {
public:
error_code ();
int code (void) const;
};
}
#endif // __NET_EXCEPT_HPP

View File

@ -1,300 +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 Danny Robson <danny@nerdcruft.net>
*/
#include "socket.hpp"
#include "../debug.hpp"
#include "../except.hpp"
#include "../cast.hpp"
#include "../log.hpp"
#include "except.hpp"
#if defined(HAVE_WINSOCK2_H)
#include <winsock2.h>
#else
#include <sys/socket.h>
#endif
#include <sys/types.h>
#include <unistd.h>
using namespace net;
//-----------------------------------------------------------------------------
template <domain D>
socket_domain<D>::socket_domain (socket_t _fd):
m_fd (_fd)
{
#ifdef __WIN32
#else
CHECK_GE (m_fd, 0);
#endif
}
#if defined(HAVE_WINSOCK2_H)
// TODO: Make this not retarded. Fucking Windows.
#define dup(X) (X)
// Winsock has incorrect return and parameter types (according to POSIX)
// so we need some wrappers around the system implementations that casts
// to expected types. Mainly int vs ssize_t returns, and int vs size_t
// parameters.
static_assert(sizeof(int) <= sizeof(ssize_t), "int != ssize_t");
static_assert(sizeof(int) <= sizeof( size_t), "int != size_t");
ssize_t recv(socket_t _socket, void *_buf, size_t _len, int _flags)
{ return (ssize_t)::recv(_socket, (char*)_buf, (int)_len, _flags); }
ssize_t recvfrom(socket_t _socket, void *_buf, size_t _len, int _flags, struct sockaddr *_sockaddr, socklen_t *_socklen)
{ return (ssize_t)::recvfrom(_socket, (char*)_buf, (int)_len, _flags, _sockaddr, (int*)_socklen); }
ssize_t sendto(socket_t _socket, const void *_buf, size_t _len, int _flags, const struct sockaddr *_sockaddr, socklen_t _socklen)
{ return (ssize_t)::sendto(_socket, (const char*)_buf, (int)_len, _flags, _sockaddr, (int)_socklen); }
ssize_t send(socket_t _socket, const void *_buf, size_t _len, int _flags)
{ return (ssize_t)::send(_socket, (const char*)_buf, (int)_len, _flags); }
#else
#define closesocket(X) close(X)
#endif
template <domain D>
socket_domain<D>::socket_domain (const socket_domain<D> &rhs):
m_fd (dup (rhs.m_fd))
{ ; }
template <domain D>
socket_domain<D>::~socket_domain () {
if (closesocket (m_fd) < 0) {
LOG_DEBUG ("closesocket: %s", strerror (errno));
}
}
template <domain D>
socket_t
socket_domain<D>::native (void) const
{ return m_fd; }
template <domain D>
void
socket_domain<D>::shutdown (void) {
#if defined(HAVE_WINSOCK2_H)
#define SHUT_SEND SD_SEND
#define SHUT_RECV SD_RECEIVE
#define SHUT_RDWR SD_BOTH
#endif
if (::shutdown (m_fd, SHUT_RDWR) < 0)
net::error::throw_code ();
}
template <domain D>
template <typename T>
T
socket_domain<D>::get_option (level, option) {
not_implemented ();
return T ();
}
template <domain D>
void
socket_domain<D>::set_option (level _level, option _option) {
if (setsockopt (this->m_fd, (int)_level, (int)_option, NULL, 0))
net::error::throw_code ();
}
template <domain D>
template <typename T>
void
socket_domain<D>::set_option (level _level, option _option, const T &value) {
if (setsockopt (this->m_fd, (int)_level, (int)_option, (const char*)&value, sizeof (value)))
net::error::throw_code ();
}
template <domain D>
void
socket_domain<D>::bind (const address_type &addr) {
typename address_type::sockaddr_type addr_in = addr.to_sockaddr ();
if (::bind (m_fd, (sockaddr *)&addr_in, sizeof (addr_in)) != 0)
net::error::throw_code ();
}
//-----------------------------------------------------------------------------
template <domain D>
net::socket<D, type::STREAM>::socket (socket_t _fd):
net::socket_domain<D> (_fd)
{ ; }
template <domain D>
net::socket<D, type::STREAM>::socket ():
net::socket_domain<D> (::socket ((int)D, (int)type::STREAM, (int)protocol::DEFAULT))
{ ; }
template <domain D>
net::socket<D, type::STREAM>::socket (const socket_type &rhs):
socket_domain<D> (rhs)
{ ; }
template <domain D>
void
net::socket<D, type::STREAM>::send (const uint8_t *restrict data, size_t len) {
CHECK (data != NULL);
CHECK_GT (len, 0);
for (size_t sent = 0; sent < len; ) {
ssize_t result = ::send (this->m_fd, static_cast<const void *>(data + sent), len - sent, 0);
if (result < 0)
net::error::throw_code ();
sent += sign_cast<size_t> (result);
}
}
template <domain D>
size_t
net::socket<D, type::STREAM>::recv (uint8_t *restrict data, size_t len) {
CHECK (data != NULL);
CHECK_GT (len, 0);
ssize_t received = ::recv (this->m_fd, data, len, 0);
if (received < 0)
net::error::throw_code ();
return sign_cast<size_t> (received);
}
template <domain D>
void
net::socket<D, type::STREAM>::connect (const address_type &_addr) {
typename address_type::sockaddr_type addr (_addr.to_sockaddr ());
if (::connect (this->m_fd, reinterpret_cast<sockaddr *> (&addr), sizeof (addr)) < 0)
net::error::throw_code ();
}
template <domain D>
void
net::socket<D, type::STREAM>::listen (const address_type &_addr, unsigned int _backlog) {
this->bind (_addr);
if (::listen (this->m_fd, sign_cast<int>(_backlog)) != 0)
net::error::throw_code ();
}
template <domain D>
typename net::socket<D, type::STREAM>::socket_ptr
net::socket<D, type::STREAM>::accept (void) {
socket_t newfd = ::accept (this->m_fd, NULL, 0);
if (newfd == INVALID_SOCKET)
net::error::throw_code ();
return socket_ptr(new socket<D, type::STREAM> (newfd));
}
template <domain D>
typename net::socket<D, type::STREAM>::address_type
net::socket<D, type::STREAM>::get_peer (void) const {
typename address_type::sockaddr_type addr;
socklen_t addr_len;
if (getpeername (this->m_fd, (sockaddr*)&addr, &addr_len))
net::error::throw_code ();
CHECK (addr_len == sizeof (addr));
return typename net::socket<D,type::STREAM>::address_type (addr);
}
//-----------------------------------------------------------------------------
template <domain D>
net::socket<D, type::DGRAM>::socket (socket_t _fd):
net::socket_domain<D> (_fd)
{ ; }
template <domain D>
net::socket<D, type::DGRAM>::socket ():
net::socket_domain<D> (::socket ((int)D, (int)type::DGRAM, (int)protocol::DEFAULT))
{ ; }
template <domain D>
net::socket<D, type::DGRAM>::socket (const socket_type &rhs):
net::socket_domain<D> (rhs)
{ ; }
template <domain D>
void
net::socket<D, type::DGRAM>::send_addr (const address_type &addr,
const uint8_t *restrict data,
size_t len) {
CHECK (data != NULL);
CHECK_GT (len, 0);
typename address_type::sockaddr_type addr_in = addr.to_sockaddr ();
ssize_t sent = ::sendto (this->m_fd, data, len, 0, (sockaddr *)&addr_in, sizeof (addr_in));
if (sent < 0)
net::error::throw_code ();
CHECK_EQ (sign_cast<size_t>(sent), len);
}
template <domain D>
typename net::socket<D, type::DGRAM>::address_type
net::socket<D, type::DGRAM>::recv_addr (uint8_t *restrict data,
size_t len) {
CHECK (data != NULL);
CHECK_GT (len, 0);
typename address_type::sockaddr_type addr_in;
socklen_t addr_len = sizeof (addr_in);
ssize_t recvd = recvfrom (this->m_fd, data, len, 0, (sockaddr *)&addr_in, &addr_len);
CHECK_EQ (sizeof (addr_in), addr_len);
if (recvd < 0)
net::error::throw_code ();
return net::socket<D,type::DGRAM>::address_type (addr_in);
}
//-----------------------------------------------------------------------------
template class net::socket_domain<domain::INET>;
template void net::socket_domain<domain::INET>::set_option<int>(level, option, const int&);
template class net::socket<domain::INET, type::STREAM>;
template class net::socket<domain::INET, type::DGRAM>;

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 2011 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __NET_SOCKET_HPP
#define __NET_SOCKET_HPP
#include <memory>
#include "types.hpp"
#include "address.hpp"
//-----------------------------------------------------------------------------
namespace net {
template <domain D>
class socket_domain {
public:
typedef address<D> address_type;
protected:
socket_t m_fd;
socket_domain (socket_t _fd);
socket_domain (const socket_domain<D>&);
~socket_domain ();
public:
socket_t native (void) const;
void shutdown (void);
template <typename T>
T get_option (level, option);
void set_option (level, option);
template <typename T>
void set_option (level, option, const T &value);
protected:
void bind (const address_type&);
};
template <domain D, type T>
class socket;
template <domain D>
class socket<D, type::STREAM>: public socket_domain<D> {
public:
typedef socket<D, type::STREAM> socket_type;
typedef std::unique_ptr<socket_type> socket_ptr;
typedef address<D> address_type;
protected:
static const unsigned int DEFAULT_BACKLOG = 5;
socket (socket_t _fd);
public:
socket ();
socket (const socket_type &);
void send (const uint8_t *restrict, size_t);
size_t recv (uint8_t *restrict, size_t);
void connect (const address_type&);
void listen (const address_type&, unsigned int backlog = DEFAULT_BACKLOG);
socket_ptr accept (void);
address_type get_peer (void) const;
};
template <domain D>
class socket<D, type::DGRAM> : public socket_domain<D> {
public:
typedef socket<D, type::DGRAM> socket_type;
typedef address<D> address_type;
socket (socket_t _fd);
public:
socket ();
socket (const socket_type &);
void send_addr (const address_type&, const uint8_t *restrict, size_t);
address_type recv_addr (uint8_t *restrict, size_t);
};
}
#endif // __NET_SOCKET_HPP

View File

@ -1,50 +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 Danny Robson <danny@nerdcruft.net>
*/
#include "types.hpp"
#include "../debug.hpp"
#if defined(HAVE_WINSOCK2_H)
#else
#include <netdb.h>
#endif
//-----------------------------------------------------------------------------
using namespace net;
//-----------------------------------------------------------------------------
protocol
net::string_to_protocol (const std::string &_name)
{ return net::string_to_protocol (_name.c_str ()); }
protocol
net::string_to_protocol (const char *_name) {
struct protoent *entry = getprotobyname (_name);
// TODO: Throw an exception...
CHECK (entry);
return (protocol)entry->p_proto;
}
std::string
net::protocol_to_string (protocol _protocol) {
struct protoent *entry = getprotobynumber ((int)_protocol);
CHECK (entry);
return entry->p_name;
}

View File

@ -1,180 +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 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __NET_TYPES_HPP
#define __NET_TYPES_HPP
#if defined(HAVE_WINSOCK2_H)
#include <winsock2.h>
#else
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <cstring>
#endif
#include <string>
#include <stdexcept>
namespace net {
/// Cross platform socket type to deal with Winsock2
#if defined(HAVE_WINSOCK2_H)
typedef SOCKET socket_t;
#else
typedef int socket_t;
const socket_t INVALID_SOCKET = -1;
#endif
/// Defines the protocol family, or communication domain of a socket (see `man socket').
enum class domain : int {
#define DEFINE_DOMAIN(V) \
V = AF_##V
DEFINE_DOMAIN(UNIX),
//DEFINE_DOMAIN(LOCAL),
DEFINE_DOMAIN(INET),
DEFINE_DOMAIN(INET6),
DEFINE_DOMAIN(IPX),
//DEFINE_DOMAIN(NETLINK),
//DEFINE_DOMAIN(X25),
//DEFINE_DOMAIN(AX25),
//DEFINE_DOMAIN(ATMPVC),
DEFINE_DOMAIN(APPLETALK)
//DEFINE_DOMAIN(PACKET)
#undef DEFINE_DOMAIN
};
/// Specifies the communication semantics of a socket; how a socket deals with data.
enum class type : int {
#define DEFINE_TYPE(V) \
V = SOCK_##V
DEFINE_TYPE(STREAM),
DEFINE_TYPE(DGRAM),
DEFINE_TYPE(SEQPACKET),
DEFINE_TYPE(RAW),
DEFINE_TYPE(RDM)
//DEFINE_TYPE(PACKET)
#undef DEFINE_TYPE
};
/// Indicates the wire transmission protocol to use.
///
/// This DOES NOT mean what you think it does! It is included for completeness sake, and unless
/// you're doing something funky with the C API you really just want DEFAULT.
/// Values retrieved from /etc/protocols
enum class protocol : int {
DEFAULT = 0,
IP = 0,
ICMP = 1,
TCP = 6,
UDP = 17,
IPV6 = 41
};
protocol
string_to_protocol (const std::string&);
protocol
string_to_protocol (const char *name);
std::string
protocol_to_string (protocol);
enum class option : int {
#define DEFINE_OPTION(V) \
V = SO_##V
DEFINE_OPTION(DEBUG),
DEFINE_OPTION(REUSEADDR),
DEFINE_OPTION(TYPE),
//DEFINE_OPTION(ERROR),
DEFINE_OPTION(DONTROUTE),
DEFINE_OPTION(BROADCAST),
//DEFINE_OPTION(SNDBUF),
DEFINE_OPTION(RCVBUF),
//DEFINE_OPTION(SNDBUFFORCE),
//DEFINE_OPTION(RCVBUFFORCE),
DEFINE_OPTION(KEEPALIVE),
DEFINE_OPTION(OOBINLINE),
//DEFINE_OPTION(NO_CHECK),
//DEFINE_OPTION(PRIORITY),
DEFINE_OPTION(LINGER),
//DEFINE_OPTION(BSDCOMPAT),
//DEFINE_OPTION(PASSCRED),
//DEFINE_OPTION(PEERCRED),
DEFINE_OPTION(RCVLOWAT),
DEFINE_OPTION(SNDLOWAT),
DEFINE_OPTION(RCVTIMEO),
DEFINE_OPTION(SNDTIMEO),
//DEFINE_OPTION(BINDTODEVICE),
//DEFINE_OPTION(ATTACH_FILTER),
//DEFINE_OPTION(DETACH_FILTER),
//DEFINE_OPTION(PEERNAME),
//DEFINE_OPTION(TIMESTAMP),
DEFINE_OPTION(ACCEPTCONN),
//DEFINE_OPTION(PEERSEC),
//DEFINE_OPTION(PASSSEC),
//DEFINE_OPTION(TIMESTAMPNS),
//DEFINE_OPTION(MARK),
//DEFINE_OPTION(TIMESTAMPING)
#undef DEFINE_OPTION
#define DEFINE_OPTION(V) \
V = TCP_##V
//DEFINE_OPTION(CORK),
//DEFINE_OPTION(DEFER_ACCEPT),
//DEFINE_OPTION(INFO),
//DEFINE_OPTION(KEEPCNT),
//DEFINE_OPTION(KEEPIDLE),
//DEFINE_OPTION(KEEPINTVL),
//DEFINE_OPTION(LINGER2),
//DEFINE_OPTION(MAXSEG),
DEFINE_OPTION(NODELAY)
//DEFINE_OPTION(QUICKACK),
//DEFINE_OPTION(SYNCNT),
//DEFINE_OPTION(WINDOW_CLAMP)
#undef DEFINE_OPTION
};
enum class level : int {
SOCKET = SOL_SOCKET,
TCP = IPPROTO_TCP
};
}
#endif // __NET_TYPES_HPP

View File

@ -27,7 +27,7 @@ using util::posix::fd;
///////////////////////////////////////////////////////////////////////////////
fd::fd (const char *path, int flags):
m_fd (open (path, flags))
m_fd (::open (path, flags))
{
if (m_fd < 0)
errno_error::throw_code ();
@ -36,7 +36,7 @@ fd::fd (const char *path, int flags):
//-----------------------------------------------------------------------------
fd::fd (const char *path, int flags, mode_t mode):
m_fd (open (path, flags, mode))
m_fd (::open (path, flags, mode))
{
if (m_fd < 0)
errno_error::throw_code ();
@ -52,21 +52,35 @@ fd::fd (fd &&rhs):
//-----------------------------------------------------------------------------
fd::fd (const fd &rhs):
m_fd (dup (rhs.m_fd))
fd::fd (int _fd):
m_fd (_fd)
{
if (m_fd < 0)
errno_error::throw_code ();
if (_fd < 0)
throw std::invalid_argument ("invalid descriptor");
}
///////////////////////////////////////////////////////////////////////////////
fd
fd::dup (void) const
{
return dup (m_fd);
}
//-----------------------------------------------------------------------------
fd::fd (int _fd):
m_fd (_fd)
{ ; }
fd
fd::dup (int _fd)
{
auto res = ::dup (_fd);
if (res < 0)
errno_error::throw_code ();
return fd (res);
}
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
fd::~fd ()
{
if (m_fd < 0)
@ -93,7 +107,3 @@ fd::operator int (void) const
{
return m_fd;
}
///////////////////////////////////////////////////////////////////////////////
const fd fd::INVALID (-1);

View File

@ -29,17 +29,18 @@ namespace util::posix {
fd (const char *path, int flags, mode_t);
fd (fd &&);
explicit fd (const fd&);
explicit fd (int);
fd (const fd&) = delete;
fd dup (void) const;
static fd dup (int);
~fd ();
struct ::stat stat (void) const;
operator int (void) const;
static const fd INVALID;
private:
int m_fd;
};

View File

@ -15,74 +15,44 @@
*/
#include "quaternion.hpp"
#include "./quaternion.hpp"
#include "maths.hpp"
#include "./debug.hpp"
#include "./maths.hpp"
#include "./vector.hpp"
#include <iostream>
//-----------------------------------------------------------------------------
using util::quaternion;
using util::matrix4;
//-----------------------------------------------------------------------------
template<> const quaternion< float> quaternion< float>::IDENTITY = { 1, 0, 0, 0 };
template<> const quaternion<double> quaternion<double>::IDENTITY = { 1, 0, 0, 0 };
template<> const quaternion<4, float> quaternion<4, float>::IDENTITY = { 1, 0, 0, 0 };
template<> const quaternion<4, double> quaternion<4, double>::IDENTITY = { 1, 0, 0, 0 };
///////////////////////////////////////////////////////////////////////////////
template <typename T>
quaternion<T>::quaternion (T _a, T _b, T _c, T _d):
a (_a),
b (_b),
c (_c),
d (_d)
{ ; }
template <size_t S, typename T>
quaternion<S,T>
quaternion<S,T>::rotation (const T radians, const vector<3,T> axis)
{
CHECK (is_normalised (axis));
//-----------------------------------------------------------------------------
template <typename T>
quaternion<T>::quaternion (T _a):
a (_a),
b (T{}),
c (T{}),
d (T{})
{ ; }
//-----------------------------------------------------------------------------
template <typename T>
quaternion<T>::quaternion ():
quaternion (T{}, T{}, T{}, T{})
{ ; }
//-----------------------------------------------------------------------------
template <typename T>
quaternion<T>::quaternion (vector3<T> v):
quaternion (0, v.x, v.y, v.z)
{ ; }
///////////////////////////////////////////////////////////////////////////////
template <typename T>
quaternion<T>
quaternion<T>::rotation (const T radians, const vector<3,T> axis) {
CHECK (axis.is_normalised ());
auto w = std::cos (radians / 2);
auto xyz = std::sin (radians / 2) * axis;
return {
std::cos (radians / 2),
std::sin (radians / 2) * axis.x,
std::sin (radians / 2) * axis.y,
std::sin (radians / 2) * axis.z
w, xyz.x, xyz.y, xyz.z
};
}
//-----------------------------------------------------------------------------
template <typename T>
quaternion<T>
quaternion<T>::rotation (vector<3,T> src, vector<3,T> dst) {
template <size_t S, typename T>
quaternion<S,T>
quaternion<S,T>::rotation (const vector<3,T> src, const vector<3,T> dst)
{
auto v = util::cross (src, dst);
return {
@ -96,195 +66,102 @@ quaternion<T>::rotation (vector<3,T> src, vector<3,T> dst) {
///////////////////////////////////////////////////////////////////////////////
template <typename T>
T
quaternion<T>::norm2 (void) const
quaternion<4,T>
util::conjugate (quaternion<4,T> q)
{
return a * a + b * b + c * c + d * d;
return { q.w, -q.x, -q.y, -q.z };
}
//-----------------------------------------------------------------------------
template <typename T>
T
quaternion<T>::norm (void) const
{
return std::sqrt (norm2 ());
}
//-----------------------------------------------------------------------------
template <typename T>
quaternion<T>
quaternion<T>::normalised (void) const
{
return *this / norm ();
}
template quaternion<4,float> util::conjugate (quaternion<4,float>);
///////////////////////////////////////////////////////////////////////////////
template <typename T>
quaternion<T>
quaternion<T>::operator- (void) const
{
return { -a, -b, -c, -d };
}
//-----------------------------------------------------------------------------
template <typename T>
quaternion<T>
quaternion<T>::conjugate (void) const
{
return { a, -b, -c, -d };
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
quaternion<T>
quaternion<T>::operator+ (const quaternion<T> q) const
template <size_t S, typename T>
quaternion<S,T>
util::operator* (const quaternion<S,T> a, const quaternion<S,T> b)
{
return {
a + q.a,
b + q.b,
c + q.c,
d + q.d
a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
};
}
template quaternion<4,float> util::operator* (quaternion<4,float>, quaternion<4,float>);
//-----------------------------------------------------------------------------
template <typename T>
quaternion<T>
quaternion<T>::operator- (const quaternion<T> q) const
template <size_t S, typename T>
quaternion<S,T>
util::operator/ (const quaternion<S,T> a, const quaternion<S,T> b)
{
return {
a - q.a,
b - q.b,
c - q.c,
d - q.d
CHECK (is_normalised (a));
CHECK (is_normalised (b));
return quaternion<S,T> {
a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z,
- a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
- a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
- a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
};
}
//-----------------------------------------------------------------------------
template <typename T>
quaternion<T>
quaternion<T>::operator* (const quaternion<T> q) const {
return {
a * q.a - b * q.b - c * q.c - d * q.d,
a * q.b + b * q.a + c * q.d - d * q.c,
a * q.c - b * q.d + c * q.a + d * q.b,
a * q.d + b * q.c - c * q.b + d * q.a,
};
}
//-----------------------------------------------------------------------------
template <typename T>
quaternion<T>
quaternion<T>::operator/ (const quaternion<T> q) const
{
auto n = q.norm2 ();
return {
( a * q.a + b * q.b + c * q.c + d * q.d) / n,
(- a * q.b + b * q.a + c * q.d - d * q.c) / n,
(- a * q.c - b * q.d + c * q.a + d * q.b) / n,
(- a * q.d + b * q.c - c * q.b + d * q.a) / n
};
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
quaternion<T>
quaternion<T>::operator+ (const T t) const
{
return { a + t, b, c, d };
}
//-----------------------------------------------------------------------------
template <typename T>
quaternion<T>
quaternion<T>::operator- (const T t) const
{
return { a - t, b, c, d };
}
//-----------------------------------------------------------------------------
template <typename T>
quaternion<T>
quaternion<T>::operator* (const T t) const
{
return { a * t, b, c, d };
}
//-----------------------------------------------------------------------------
template <typename T>
quaternion<T>
quaternion<T>::operator/ (const T t) const
{
return { a / t, b, c, d };
}
template quaternion<4,float> util::operator/ (quaternion<4,float>, quaternion<4,float>);
///////////////////////////////////////////////////////////////////////////////
template <typename T>
bool
quaternion<T>::operator== (const quaternion<T> rhs) const
template <size_t S, typename T>
util::matrix4<T>
quaternion<S, T>::as_matrix (void) const
{
return almost_equal (a, rhs.a) &&
almost_equal (b, rhs.b) &&
almost_equal (c, rhs.c) &&
almost_equal (d, rhs.d);
}
CHECK (is_normalised (*this));
//-----------------------------------------------------------------------------
template <typename T>
bool
quaternion<T>::operator!= (const quaternion<T> rhs) const
{
return !(*this == rhs);
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
matrix4<T>
quaternion<T>::rotation_matrix (void) const
{
CHECK_EQ (T{1}, norm ());
const T wx = w * x, wy = w * y, wz = w * z;
const T xx = x * x, xy = x * y, xz = x * z;
const T yy = y * y, yz = y * z, zz = z * z;
const T wx = this->w * this->x, wy = this->w * this->y, wz = this->w * this->z;
const T xx = this->x * this->x, xy = this->x * this->y, xz = this->x * this->z;
const T yy = this->y * this->y, yz = this->y * this->z, zz = this->z * this->z;
return { {
{ 1 - 2 * (yy - zz), 2 * (xy - wz), 2 * (xz + wy), 0 },
{ 2 * (xy + wz), 1 - 2 * (xx - zz), 2 * (yz - wx), 0 },
{ 2 * (xz - wy), 2 * (yz + wx), 1 - 2 * (xx - yy), 0 },
{ 1 - 2 * (yy + zz), 2 * (xy - wz), 2 * (xz + wy), 0 },
{ 2 * (xy + wz), 1 - 2 * (xx + zz), 2 * (yz - wx), 0 },
{ 2 * (xz - wy), 2 * (yz + wx), 1 - 2 * (xx + yy), 0 },
{ 0, 0, 0, 1 }
} };
}
///////////////////////////////////////////////////////////////////////////////
template <typename T>
template <size_t S, typename T>
std::ostream&
util::operator<< (std::ostream &os, quaternion<T> q)
util::operator<< (std::ostream &os, const quaternion<S,T> q)
{
os << q.w << ' ' << q.x << "i " << q.y << "j " << q.z << 'k';
return os;
return os << "[" << q.w << ", " << q.x << ", " << q.y << ", " << q.z << "]";
}
///////////////////////////////////////////////////////////////////////////////
template struct util::quaternion<float>;
template struct util::quaternion<double>;
//-----------------------------------------------------------------------------
template std::ostream& util::operator<< (std::ostream&, quaternion<4,float>);
template std::ostream& util::operator<< (std::ostream&, quaternion<4,double>);
template std::ostream& util::operator<< (std::ostream&, quaternion<float>);
template std::ostream& util::operator<< (std::ostream&, quaternion<double>);
///////////////////////////////////////////////////////////////////////////////
namespace util { namespace debug {
template <size_t S, typename T>
struct validator<quaternion<S,T>> {
static bool is_valid (const quaternion<S,T> &q)
{
return is_normalised (q);
}
};
} }
//-----------------------------------------------------------------------------
template bool util::debug::is_valid(const quaternion<4,float>&);
template bool util::debug::is_valid(const quaternion<4,double>&);
///////////////////////////////////////////////////////////////////////////////
template struct util::quaternion<4,float>;
template struct util::quaternion<4,double>;

View File

@ -17,6 +17,8 @@
#ifndef __UTIL_QUATERNION_HPP
#define __UTIL_QUATERNION_HPP
#include "coord.hpp"
#include "vector.hpp"
#include "matrix.hpp"
@ -24,53 +26,46 @@
namespace util {
template <typename T>
struct quaternion {
///////////////////////////////////////////////////////////////////////
union {
struct { T w, x, y, z; };
struct { T a, b, c, d; };
T data[4];
};
// quaternions must be 4 elements, but we include a size parameter so it
// fits with the generic coord infrastructure more easily.
//
// specifically:
// large regions of base code require a template template parameter with
// size and type arguments, which is annoying to work around for this one
// case.
//
// we protect against invalid instantiations through static_assert
template <size_t S, typename T>
struct quaternion : public coord::base<4,T,quaternion,coord::wxyz,coord::abcd> {
static_assert (S == 4, "quaternions must be 4 elements");
static const quaternion IDENTITY;
using coord::base<S,T,::util::quaternion,::util::coord::wxyz,::util::coord::abcd>::base;
static quaternion rotation (T radians, vector<3,T> axis);
static quaternion rotation (vector<3,T> src, vector<3,T> dst);
quaternion (T a, T b, T c, T d);
quaternion (T a);
quaternion ();
quaternion (vector<3,T>);
matrix4<T> as_matrix (void) const;
T norm (void) const;
T norm2 (void) const;
quaternion normalised (void) const;
quaternion operator- (void) const;
quaternion conjugate (void) const;
quaternion operator+ (const quaternion) const;
quaternion operator- (const quaternion) const;
quaternion operator* (const quaternion) const;
quaternion operator/ (const quaternion) const;
quaternion operator+ (const T) const;
quaternion operator- (const T) const;
quaternion operator* (const T) const;
quaternion operator/ (const T) const;
bool operator== (const quaternion) const;
bool operator!= (const quaternion) const;
matrix4<T> rotation_matrix (void) const;
static const quaternion IDENTITY;
};
typedef quaternion<float> quaternionf;
template <typename T>
quaternion<4,T>
conjugate (quaternion<4,T>);
template <size_t S, typename T>
quaternion<S,T>
operator* (const quaternion<S,T>, const quaternion<S,T>);
template <size_t S, typename T>
quaternion<S,T>
operator/ (const quaternion<S,T>, const quaternion<S,T>);
typedef quaternion<4,float> quaternionf;
template <size_t S, typename T>
std::ostream&
operator<< (std::ostream&, quaternion<T>);
operator<< (std::ostream&, quaternion<S,T>);
}

View File

@ -19,7 +19,7 @@
#define __UTIL_RANGE_HPP
#include <cstdint>
#include <iostream>
#include <ostream>
namespace util {
/**

View File

@ -372,11 +372,11 @@ util::operator<< (std::ostream &os, const util::region<S,T> &rhs) {
///////////////////////////////////////////////////////////////////////////////
namespace util { namespace debug {
template <size_t S, typename T>
struct validator<util::region,S,T> {
struct validator<util::region<S,T>> {
static bool is_valid (const util::region<S,T> &r)
{
CHECK_GE (r.area (), 0);
CHECK_GE (min (r.e), 0);
CHECK_GE (r.area (), 0u);
CHECK_GE (min (r.e), 0u);
return r.area () >= 0 && min (r.e) >= 0;
}
@ -388,7 +388,7 @@ namespace util { namespace debug {
#define INSTANTIATE_S_T(S,T) \
template struct util::region<S,T>; \
template std::ostream& util::operator<< (std::ostream&, const region<S,T>&); \
template struct util::debug::validator<util::region,S,T>;
template struct util::debug::validator<util::region<S,T>>;
#define INSTANTIATE(T) \
INSTANTIATE_S_T(2,T) \

View File

@ -17,7 +17,7 @@
#ifndef __UTIL_STATS_HPP
#define __UTIL_STATS_HPP
#include <iostream>
#include <ostream>
namespace util {

View File

@ -17,7 +17,7 @@
#ifndef __UTIL_STREAM_HPP
#define __UTIL_STREAM_HPP
#include <iostream>
#include <ostream>
namespace util {
namespace stream {

44
tap.hpp
View File

@ -37,42 +37,42 @@ namespace util { namespace TAP {
~logger ();
//---------------------------------------------------------------------
template <typename ...Args>
void expect (bool, const std::string &fmt, Args&&...);
template <typename ...Args, size_t N>
void expect (bool, const char (&fmt)[N], Args&&...);
template <typename ...Args>
void expect (const std::function<bool(Args...)>&, Args&&..., const std::string& msg);
template <typename ...Args, size_t N>
void expect (const std::function<bool(Args...)>&, Args&&..., const char (&msg)[N]);
//---------------------------------------------------------------------
template <typename T, typename U, typename ...Args>
void expect_eq (const T&, const U&, const std::string &fmt, Args&&...);
template <typename T, typename U, typename ...Args, size_t N>
void expect_eq (const T&, const U&, const char (&fmt)[N], Args&&...);
template <typename T, typename U, typename ...Args>
void expect_neq (const T&, const U&, const std::string &fmt, Args&&...);
template <typename T, typename U, typename ...Args, size_t N>
void expect_neq (const T&, const U&, const char (&fmt)[N], Args&&...);
//---------------------------------------------------------------------
template <typename T, typename U, typename ...Args>
void expect_gt (const T&, const U&, const std::string &fmt, Args&&...);
template <typename T, typename U, typename ...Args, size_t N>
void expect_gt (const T&, const U&, const char (&fmt)[N], Args&&...);
template <typename T, typename U, typename ...Args>
void expect_ge (const T&, const U&, const std::string &fmt, Args&&...);
template <typename T, typename U, typename ...Args, size_t N>
void expect_ge (const T&, const U&, const char (&fmt)[N], Args&&...);
template <typename T, typename U, typename ...Args>
void expect_lt (const T&, const U&, const std::string &fmt, Args&&...);
template <typename T, typename U, typename ...Args, size_t N>
void expect_lt (const T&, const U&, const char (&fmt)[N], Args&&...);
template <typename T, typename U, typename ...Args>
void expect_le (const T&, const U&, const std::string &fmt, Args&&...);
template <typename T, typename U, typename ...Args, size_t N>
void expect_le (const T&, const U&, const char (&fmt)[N], Args&&...);
//---------------------------------------------------------------------
template <typename T, typename ...Args>
void expect_nan (const T&, const std::string &fmt, Args&&...);
template <typename T, typename ...Args, size_t N>
void expect_nan (const T&, const char (&fmt)[N], Args&&...);
//---------------------------------------------------------------------
template <typename T, typename ...Args>
void expect_nothrow (T&&, const std::string &fmt, Args&&...);
template <typename T, typename ...Args, size_t N>
void expect_nothrow (T&&, const char (&fmt)[N], Args&&...);
template <typename E, typename T, typename ...Args>
void expect_throw (T&&, const std::string &fmt, Args&&...);
template <typename E, typename T, typename ...Args, size_t N>
void expect_throw (T&&, const char (&fmt)[N], Args&&...);
//---------------------------------------------------------------------
void skip (const std::string &msg);

88
tap.ipp
View File

@ -29,9 +29,9 @@
///////////////////////////////////////////////////////////////////////////////
template <typename ...Args>
template <typename ...Args, size_t N>
void
util::TAP::logger::expect (bool test, const std::string &fmt, Args&&... args)
util::TAP::logger::expect (bool test, const char (&fmt)[N], Args&&... args)
{
std::cout << (test ? "ok " : "not ok ") << ++m_size
<< " - "
@ -43,61 +43,46 @@ util::TAP::logger::expect (bool test, const std::string &fmt, Args&&... args)
//-----------------------------------------------------------------------------
template <typename... Args>
template <typename ...Args, size_t N>
void
util::TAP::logger::expect (const std::function<bool(Args...)> &test, Args&&... args, const std::string &msg)
util::TAP::logger::expect (const std::function<bool(Args...)> &test, Args&&... args, const char (&fmt)[N])
{
expect (test (std::forward<Args> (args)...), msg);
try {
expect (test (std::forward<Args> (args)...), fmt);
} catch (...) {
expect (false, fmt);
}
}
///////////////////////////////////////////////////////////////////////////////
template <typename T, typename U, typename ...Args, size_t N>
void
util::TAP::logger::expect_eq (const T&a, const U &b, const char (&fmt)[N], Args&&... args)
{
expect (almost_equal (a, b), fmt, std::forward<Args> (args)...);
}
//-----------------------------------------------------------------------------
template <typename T, typename U, typename ...Args>
template <typename T, typename U, typename ...Args, size_t N>
void
util::TAP::logger::expect_eq (const T&a, const U &b, const std::string &fmt, Args&&... args)
util::TAP::logger::expect_neq (const T&a, const U &b, const char (&fmt)[N], Args&&... args)
{
static const std::function<bool(const T&,const U&)> TEST = [] (const T &t, const U &u) -> bool {
return almost_equal (t, u);
};
expect<const T&, const U&> (TEST, a, b, util::format::render (fmt, std::forward<Args> (args)...));
expect (!almost_equal (a, b), fmt, std::forward<Args> (args)...);
}
//-----------------------------------------------------------------------------
template <typename T, typename U, typename ...Args>
void
util::TAP::logger::expect_neq (const T&a, const U &b, const std::string &fmt, Args&&... args)
{
static const std::function<bool(const T&,const U&)> TEST = [] (const T &t, const U &u) -> bool {
return !almost_equal (t, u);
};
expect<const T&, const U&> (TEST, a, b, util::format::render (fmt, std::forward<Args> (args)...));
}
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
#define TAP_TEST(SUFFIX,OP) \
template <typename T, typename U, typename ...Args> \
template <typename T, typename U, typename ...Args, size_t N> \
void \
util::TAP::logger::expect_ ## SUFFIX (const T &a, \
const U &b, \
const std::string &fmt, \
const char (&fmt)[N], \
Args&&... args) \
{ \
static const std::function< \
bool(const T&,const U&) \
> TEST = [] (const T&t, const U&u) { return t OP u; }; \
\
expect<const T&, const U&> ( \
TEST, \
a, b, \
util::format::render ( \
fmt, \
std::forward<Args> (args)... \
) \
); \
expect ((a) OP (b), fmt, std::forward<Args> (args)...); \
}
TAP_TEST(gt, > )
@ -109,23 +94,18 @@ TAP_TEST(le, <=)
//-----------------------------------------------------------------------------
template <typename T, typename ...Args>
template <typename T, typename ...Args, size_t N>
void
util::TAP::logger::expect_nan (const T &t, const std::string &fmt, Args&&... args)
util::TAP::logger::expect_nan (const T &t, const char (&fmt)[N], Args&&... args)
{
bool(*func)(T) = std::isnan;
expect<const T&> (
std::function<bool(const T&)> (func),
t,
util::format::render (fmt, std::forward<Args> (args)...)
);
expect (std::isnan (t), fmt, std::forward<Args> (args)...);
}
//-----------------------------------------------------------------------------
template <typename T, typename ...Args>
template <typename T, typename ...Args, size_t N>
void
util::TAP::logger::expect_nothrow (T &&t, const std::string &fmt, Args&&... args)
util::TAP::logger::expect_nothrow (T &&t, const char (&fmt)[N], Args&&... args)
{
bool success = true;
@ -135,14 +115,14 @@ util::TAP::logger::expect_nothrow (T &&t, const std::string &fmt, Args&&... args
success = false;
}
expect (success, util::format::render (fmt, std::forward<Args> (args)...));
expect (success, fmt, std::forward<Args> (args)...);
}
//-----------------------------------------------------------------------------
template <typename E, typename T, typename ...Args>
template <typename E, typename T, typename ...Args, size_t N>
void
util::TAP::logger::expect_throw (T &&t, const std::string &fmt, Args&&... args)
util::TAP::logger::expect_throw (T &&t, const char (&fmt)[N], Args&&... args)
{
bool success = false;
@ -154,5 +134,5 @@ util::TAP::logger::expect_throw (T &&t, const std::string &fmt, Args&&... args)
success = false;
}
expect (success, util::format::render (fmt, std::forward<Args> (args)...));
expect (success, fmt, std::forward<Args> (args)...);
}

73
test/affine.cpp Normal file
View File

@ -0,0 +1,73 @@
#include "tap.hpp"
#include "vector.hpp"
#include "matrix.hpp"
#include "quaternion.hpp"
///////////////////////////////////////////////////////////////////////////////
void
test_mq_axis (util::TAP::logger &tap)
{
static const struct {
util::vector3f euler;
const char *msg;
} TESTS[] = {
{ { 1, 0, 0 }, "x-axis" },
{ { 0, 1, 0 }, "y-axis" },
{ { 0, 0, 1 }, "z-axis" },
};
for (auto t: TESTS) {
auto m = util::matrix4f::rotation (1, t.euler);
auto q = util::quaternionf::rotation (1, t.euler);
auto diff = sum (abs (m - q.as_matrix ()));
tap.expect_le (diff, 1e-6f, "matrix/quaternion rotation identities, %s", t.msg);
}
}
///////////////////////////////////////////////////////////////////////////////
void
test_mq_euler (util::TAP::logger &tap)
{
static const struct {
util::vector3f euler;
const char *msg;
} TESTS[] = {
{ { 0, 0, 0 }, "zeroes" },
{ { 1, 0, 0 }, "x-axis" },
{ { 0, 1, 0 }, "y-axis" },
{ { 0, 0, 1 }, "z-axis" },
{ { 1, 1, 1 }, "ones" },
{ { 9, 9, 9 }, "nines" }
};
for (auto t: TESTS) {
auto m = util::matrix4f::rotation (t.euler[0], { 1, 0, 0 }) *
util::matrix4f::rotation (t.euler[1], { 0, 1, 0 }) *
util::matrix4f::rotation (t.euler[2], { 0, 0, 1 });
auto q = (
util::quaternionf::rotation (t.euler[0], { 1, 0, 0 }) *
util::quaternionf::rotation (t.euler[1], { 0, 1, 0 }) *
util::quaternionf::rotation (t.euler[2], { 0, 0, 1 })
).as_matrix ();
auto diff = util::sum (abs (m - q));
tap.expect_le (diff, 1e-6f, "matrix-quaternion xyz euler rotations, %s", t.msg);
}
}
///////////////////////////////////////////////////////////////////////////////
int
main (int, char**)
{
util::TAP::logger tap;
test_mq_axis (tap);
test_mq_euler (tap);
return tap.status ();
}

View File

@ -7,6 +7,8 @@ static char g_backing[1024*1024];
struct setter {
setter (const setter&) = delete;
setter (bool &_target):
target (_target)
{ target = false; }
@ -30,7 +32,7 @@ main (void)
// double check our testing object is working, because I'm tired and stupid
{
auto val = setter (flag);
setter val (flag);
CHECK (!flag);
}
CHECK (flag);

View File

@ -86,13 +86,13 @@ test_bool (util::TAP::logger &tap)
for (auto i: positive) {
argv[2] = i;
p.scan (argv.size (), argv.data ());
tap.expect_eq (value, true, i, "read bool, %s", i);
tap.expect_eq (value, true, "read bool, %s", i);
}
for (auto i: negative) {
argv[2] = i;
p.scan (argv.size (), argv.data ());
tap.expect_eq (value, false, i, "read bool, %s", i);
tap.expect_eq (value, false, "read bool, %s", i);
}
// Check that invalid forms of boolean all throw exceptions

View File

@ -2,6 +2,7 @@
#include "tap.hpp"
int
main (int, char**)
{
@ -44,8 +45,8 @@ main (int, char**)
};
for (auto i: TESTS) {
tap.expect_eq (util::rgb_to_hsv (i.rgb), i.hsv, i.name);
tap.expect_eq (util::hsv_to_rgb (i.hsv), i.rgb, i.name);
tap.expect_eq (util::rgb_to_hsv (i.rgb), i.hsv, "rgb-to-hsv %s", i.name);
tap.expect_eq (util::hsv_to_rgb (i.hsv), i.rgb, "hsv-to-rgb %s", i.name);
}
}
}

View File

@ -1,5 +1,6 @@
#include "tap.hpp"
#include "point.hpp"
#include "vector.hpp"
#include "coord/iostream.hpp"
@ -30,5 +31,10 @@ main (void)
"unary point boolean negation has type bool"
);
auto vec = util::vector4f (0.5f);
t.expect_eq (vec, util::normalised (vec), "normalisation of normalised vector");
t.expect_eq (sum (util::vector4f::ONES), 4.f, "elementwise summation");
return t.status ();
}

View File

@ -2,6 +2,7 @@
#include "tap.hpp"
#include "types.hpp"
int
main ()
{
@ -384,8 +385,6 @@ main ()
success = success && std::equal (std::begin (data), std::end (data), std::begin (t.data[j]));
};
std::ostringstream os;
os << "ARC4: " << i;
tap.expect (success, os.str ());
tap.expect (success, "ARC4 %zu", i);
}
}

View File

@ -50,17 +50,8 @@ main ()
std::array<uint32_t,2> dec (t.enc);
gen.decrypt (dec.data (), dec.size ());
{
std::ostringstream os;
os << "TEA_enc " << i;
tap.expect (enc == t.enc, os.str ());
}
{
std::ostringstream os;
os << "TEA_dec " << i;
tap.expect (dec == t.dec, os.str ());
}
tap.expect (enc == t.enc, "TEA_enc %zu", i);
tap.expect (dec == t.dec, "TEA_dec %zu", i);
}
return tap.status ();

View File

@ -49,17 +49,8 @@ main ()
std::array<uint32_t,2> dec (t.enc);
gen.decrypt (dec.data (), dec.size ());
{
std::ostringstream os;
os << "XTEA_enc " << i;
tap.expect (enc == t.enc, os.str ());
}
{
std::ostringstream os;
os << "XTEA_dec " << i;
tap.expect (dec == t.dec, os.str ());
}
tap.expect (enc == t.enc, "XTEA_enc %zu", i);
tap.expect (dec == t.dec, "XTEA_dec %zu", i);
}
return tap.status ();

View File

@ -104,17 +104,8 @@ main ()
std::vector<uint32_t> dec (enc);
gen.decrypt (dec.data (), dec.size ());
{
std::ostringstream os;
os << "XXTEA_enc " << i;
tap.expect (enc == t.enc, os.str ());
}
{
std::ostringstream os;
os << "XXTEA_dec " << i;
tap.expect (dec == t.dec, os.str ());
}
tap.expect (enc == t.enc, "XXTEA_enc %zu", i);
tap.expect (dec == t.dec, "XXTEA_dec %zu", i);
}
return tap.status ();

View File

@ -16,19 +16,19 @@ test_simple (util::TAP::logger &tap)
std::ostringstream os;
os << "fixed<" << type_to_string<T> () << ',' << I << ',' << E << '>';
tap.expect_eq (lo, lo, os.str () + " self equality");
tap.expect_eq (hi, hi, os.str () + " self equality");
tap.expect_eq (lo, lo, "%s self equality", os.str ());
tap.expect_eq (hi, hi, "%s self equality", os.str ());
tap.expect_neq (hi, lo, os.str () + " inequality");
tap.expect_neq (lo, hi, os.str () + " inequality");
tap.expect_neq (hi, lo, "%s inequality", os.str ());
tap.expect_neq (lo, hi, "%s inequality", os.str ());
tap.expect_lt (lo, hi, os.str () + " less than");
tap.expect_le (lo, hi, os.str () + " less than equal");
tap.expect_le (lo, lo, os.str () + " less than equal");
tap.expect_lt (lo, hi, "%s less than", os.str ());
tap.expect_le (lo, hi, "%s less than equal", os.str ());
tap.expect_le (lo, lo, "%s less than equal", os.str ());
tap.expect_gt (hi, lo, os.str () + " greater than");
tap.expect_ge (lo, lo, os.str () + " greater than equal");
tap.expect_ge (hi, lo, os.str () + " greater than equal");
tap.expect_gt (hi, lo, "%s greater than", os.str ());
tap.expect_ge (lo, lo, "%s greater than equal", os.str ());
tap.expect_ge (hi, lo, "%s greater than equal", os.str ());
}

View File

@ -2,28 +2,211 @@
#include "tap.hpp"
///////////////////////////////////////////////////////////////////////////////
struct userobj { };
static std::ostream&
operator<< (std::ostream &os, const userobj&)
{
return os << "userobj";
}
///////////////////////////////////////////////////////////////////////////////
int
main (void)
{
using namespace std::string_literals;
util::TAP::logger tap;
tap.expect_eq (util::format::render ("identity"), "identity"s, "identity literal");
tap.expect_eq (util::format::render ("%s", "identity"s), "identity"s, "identity string substitution");
tap.expect_eq (util::format::render ("%s", "identity" ), "identity"s, "identity char[] substitution");
#define CHECK_RENDER(fmt,res,...) do { \
auto val = util::format::render (fmt, ##__VA_ARGS__); \
tap.expect_eq (val, res, "render '%s'", fmt); \
} while (0)
tap.expect_throw<util::format::missing_error> ([] (void) {
util::format::render ("%s");
}, "missing value");
CHECK_RENDER ("foo", "foo");
tap.expect_throw<util::format::invalid_specifier<int>> ([] (void) {
util::format::render ("%<", 42);
}, "invalid specifier");
CHECK_RENDER ("%i", "1", 1 );
CHECK_RENDER ("%3i", " 1", 1 );
CHECK_RENDER ("%03i", "001", 1 );
CHECK_RENDER ("%.i", "", 0);
CHECK_RENDER ("% .i", " ", 0); // zero precision still requires a space
tap.expect_throw<util::format::format_error> ([] (void) {
util::format::render ("%", 42);
}, "truncated specifier");
CHECK_RENDER ("%hhi", "1", (signed char)1);
CHECK_RENDER ("%hi", "1", (signed short)1);
CHECK_RENDER ("%li", "1", (signed long)1);
CHECK_RENDER ("%lli", "1", (signed long long)1);
CHECK_RENDER ("%ji", "1", (intmax_t)1);
CHECK_RENDER ("%zi", "1", (ssize_t)1);
CHECK_RENDER ("%ti", "1", (ptrdiff_t)1);
return tap.status ();
CHECK_RENDER ("%u", "1", 1u);
CHECK_RENDER ("%03u", "001", 1u);
CHECK_RENDER ("% u", " 1", 1u);
CHECK_RENDER ("% 3u", " 1", 1u);
CHECK_RENDER ("% 03u", " 01", 1u);
CHECK_RENDER ("%-3u", "1 ", 1u);
CHECK_RENDER ("%64u", " 1", 1u);
CHECK_RENDER ("%hhu", "1", (unsigned char)1);
CHECK_RENDER ("%hu", "1", (unsigned short)1);
CHECK_RENDER ("%lu", "1", (unsigned long)1);
CHECK_RENDER ("%llu", "1", (unsigned long long)1);
CHECK_RENDER ("%ju", "1", (uintmax_t)1);
CHECK_RENDER ("%zu", "0", (size_t)0);
CHECK_RENDER ("%zu", "1", (size_t)1);
CHECK_RENDER ("%!", "1", 1u);
CHECK_RENDER ("%o", "1", 01u);
CHECK_RENDER ("%o", "13", 013u);
CHECK_RENDER ("%o", "13", 013u);
CHECK_RENDER ("%#o", "013", 013u);
CHECK_RENDER ("%x", "1", 0x1u);
CHECK_RENDER ("%x", "fe", 0xfeu);
CHECK_RENDER ("%X", "FE", 0xFEu);
CHECK_RENDER ("%#x", "0xfe", 0xfeu);
CHECK_RENDER ("%#X", "0XFE", 0xFEu);
CHECK_RENDER ("%e", "1.000000e+00", 1.);
CHECK_RENDER ("%e", "1.200000e+00", 1.2);
CHECK_RENDER ("%e", "1.234568e+00", 1.2345678);
CHECK_RENDER ("%E", "1.234568E+00", 1.2345678);
CHECK_RENDER ("%f", "1.000000", 1.);
CHECK_RENDER ("%f", "1.200000", 1.2);
CHECK_RENDER ("%f", "1.234560", 1.23456);
CHECK_RENDER ("%f", "1.234567", 1.234567);
CHECK_RENDER ("%f", "1.234568", 1.2345678);
CHECK_RENDER ("%g", "1", 1.);
CHECK_RENDER ("%g", "1.2", 1.2);
CHECK_RENDER ("%g", "1.23457", 1.2345678);
CHECK_RENDER ("%g", "0.000123457", 0.00012345678);
CHECK_RENDER ("%g", "1.23457e-05", 0.000012345678);
CHECK_RENDER ("%G", "1.23457E-05", 0.000012345678);
CHECK_RENDER ("%+e", "+1.234568e+00", 1.2345678);
CHECK_RENDER ("%+f", "+1.234568", 1.2345678);
CHECK_RENDER ("%+g", "+1.23457", 1.2345678);
CHECK_RENDER ("%+a", "+0x1.3c0ca2a5b1d5dp+0", 1.2345678);
CHECK_RENDER ("%#.e", "1.e+00", 1.2345678);
CHECK_RENDER ("%#.f", "1.", 1.2345678);
CHECK_RENDER ("%#.g", "1.", 1.2345678);
//CHECK_RENDER ("%#.a", "0x1.p+0", 1.2345678);
CHECK_RENDER ("%a", "0x1.3c0ca2a5b1d5dp+0", 1.2345678);
CHECK_RENDER ("%A", "0X1.3C0CA2A5B1D5DP+0", 1.2345678);
CHECK_RENDER ("%e", "inf", std::numeric_limits<double>::infinity ());
CHECK_RENDER ("%E", "INF", std::numeric_limits<double>::infinity ());
CHECK_RENDER ("%f", "inf", std::numeric_limits<double>::infinity ());
CHECK_RENDER ("%F", "INF", std::numeric_limits<double>::infinity ());
CHECK_RENDER ("%g", "inf", std::numeric_limits<double>::infinity ());
CHECK_RENDER ("%G", "INF", std::numeric_limits<double>::infinity ());
CHECK_RENDER ("%a", "inf", std::numeric_limits<double>::infinity ());
CHECK_RENDER ("%A", "INF", std::numeric_limits<double>::infinity ());
CHECK_RENDER ("%e", "nan", std::numeric_limits<double>::quiet_NaN ());
CHECK_RENDER ("%E", "NAN", std::numeric_limits<double>::quiet_NaN ());
CHECK_RENDER ("%f", "nan", std::numeric_limits<double>::quiet_NaN ());
CHECK_RENDER ("%F", "NAN", std::numeric_limits<double>::quiet_NaN ());
CHECK_RENDER ("%g", "nan", std::numeric_limits<double>::quiet_NaN ());
CHECK_RENDER ("%G", "NAN", std::numeric_limits<double>::quiet_NaN ());
CHECK_RENDER ("%a", "nan", std::numeric_limits<double>::quiet_NaN ());
CHECK_RENDER ("%A", "NAN", std::numeric_limits<double>::quiet_NaN ());
CHECK_RENDER ("%.f", "1", 1.2345678);
CHECK_RENDER ("%3.f", " 1", 1.2345678);
CHECK_RENDER ("%3.2f", "1.23", 1.2345678);
CHECK_RENDER ("%3.2f", "1234.57", 1234.5678);
CHECK_RENDER ("%!", "1", 1.);
CHECK_RENDER ("%c", "A", 'A');
CHECK_RENDER ("%!", "A", 'A');
CHECK_RENDER ("%s", "foo", "foo");
CHECK_RENDER ("%s", "foo", std::string ("foo"));
CHECK_RENDER ("%s", "foo", const_cast<char*> ("foo"));
CHECK_RENDER ("%.s", "", "foo");
CHECK_RENDER ("%.0s", "", "foo");
CHECK_RENDER ("%.2s", "fo", "foo");
CHECK_RENDER ("%.02s", "fo", "foo");
CHECK_RENDER ("%.64s", "foo", "foo");
CHECK_RENDER ("%3.1s", " f", "foo");
CHECK_RENDER ("%-3.1s", "f ", "foo");
CHECK_RENDER ("%!", "foo", "foo");
CHECK_RENDER ("%!", "userobj", userobj {});
CHECK_RENDER ("%p", "0x1234567", (void*)0x01234567);
CHECK_RENDER ("%p", "0x1234567", (int*)0x01234567);
CHECK_RENDER ("%p", "0x1234567", (char*)0x01234567);
CHECK_RENDER ("%p", "(nil)", nullptr);
CHECK_RENDER ("%p", "(nil)", NULL);
CHECK_RENDER ("%!", "0x1234567", (void*)0x01234567);
CHECK_RENDER ("%%", "%");
CHECK_RENDER ("%10%", "%");
CHECK_RENDER ("%.%", "%");
CHECK_RENDER ("% 0-+#12.34%", "%"); // escaped conversions should largely ignore flags, width, and precision.
// multiple components
CHECK_RENDER ("%%%%", "%%");
CHECK_RENDER (" %%", " %");
CHECK_RENDER ("%% ", "% ");
CHECK_RENDER ("%% %%", "% %");
CHECK_RENDER (" %% %% ", " % % ");
CHECK_RENDER ("%u %u", "1 2", 1u, 2u);
CHECK_RENDER ("%#o %o", "010 10", 8u, 8u);
CHECK_RENDER ("%#o %o %#o", "010 10 010", 8u, 8u, 8u);
CHECK_RENDER ("%X%x%X", "FfF", 0xfu, 0xfu, 0xfu);
tap.expect_eq (util::format::render ("%u\n", 1u), "1\n", "newline");
#define CHECK_THROW(fmt,except,...) do { \
tap.expect_throw<util::format::except> ([&] { \
util::format::render (fmt, ##__VA_ARGS__); \
}, "exception '%s' for format '%s'", #except, fmt); \
} while (0)
CHECK_THROW("%", syntax_error);
CHECK_THROW("%_", syntax_error);
CHECK_THROW("%_u", syntax_error);
CHECK_THROW("%u", missing_error);
CHECK_THROW("%!", missing_error);
CHECK_THROW("%d", conversion_error, 1u);
CHECK_THROW("%i", conversion_error, 1u);
CHECK_THROW("%i", conversion_error, nullptr);
CHECK_THROW("%hhi", length_error, (long long)1);
//CHECK_THROW("%lli", length_error, (signed char)1);
CHECK_THROW("%u", conversion_error, 1.);
CHECK_THROW("%u", conversion_error, "foo");
CHECK_THROW("%u", conversion_error, (void*)0);
CHECK_THROW("%u", conversion_error, 1);
CHECK_THROW("%u", conversion_error, nullptr);
CHECK_THROW("%hhu", length_error, (unsigned long long)1);
//CHECK_THROW("%llu", length_error, (unsigned char)1);
CHECK_THROW("%f", conversion_error, 1u);
CHECK_THROW("%f", conversion_error, "foo");
CHECK_THROW("%f", conversion_error, nullptr);
CHECK_THROW("%s", conversion_error, 1u);
CHECK_THROW("%s", conversion_error, '_');
CHECK_THROW("%s", conversion_error, nullptr);
CHECK_THROW("%c", conversion_error, 1u);
CHECK_THROW("%c", conversion_error, "foo");
}

View File

@ -274,7 +274,7 @@ main (int, char**)
util::TAP::logger tap;
for (size_t i = 0; i < elems (TESTS); ++i)
tap.expect (TESTS[i].fun (TESTS[i].key, TESTS[i].dat, TESTS[i].res), "standard test vector %u", i);
tap.expect (TESTS[i].fun (TESTS[i].key, TESTS[i].dat, TESTS[i].res), "standard test vector %zu", i);
return tap.status ();
}

View File

@ -116,7 +116,7 @@ main(int, char**) {
obj.update (reinterpret_cast<const uint8_t*> (i.data), strlen (i.data));
obj.finish ();
tap.expect_eq (obj.digest (), i.output, i.msg);
tap.expect_eq (obj.digest (), i.output, "%s", i.msg);
}
// Perform 'million-a' check

View File

@ -66,7 +66,7 @@ main (int, char**)
obj.update (reinterpret_cast<const uint8_t*> (i.input), strlen (i.input));
obj.finish ();
tap.expect_eq (obj.digest (), i.output, i.msg);
tap.expect_eq (obj.digest (), i.output, "%s", i.msg);
}
return tap.status ();

View File

@ -55,7 +55,7 @@ main (int, char **) {
obj.update (reinterpret_cast<const uint8_t*> (i.input), strlen (i.input));
obj.finish ();
tap.expect_eq (obj.digest (), i.output, i.msg);
tap.expect_eq (obj.digest (), i.output, "%s", i.msg);
}
return tap.status ();

View File

@ -23,9 +23,8 @@ test_good (util::TAP::logger &tap)
{ "127.0.0.1", { 127, 0, 0, 1 }, "localhost" }
};
for (const auto &i: TESTS) {
tap.expect_eq (ipv4::ip::parse (i.str), i.ip, i.msg);
}
for (const auto &i: TESTS)
tap.expect_eq (ipv4::ip::parse (i.str), i.ip, "%s", i.msg);
}
@ -43,9 +42,8 @@ test_bad (util::TAP::logger &tap)
{ "256.0.0.1", "overflow" }
};
for (const auto &i: TESTS) {
tap.expect_throw<ipv4::error> ([&] { ipv4::ip::parse (i.str); }, i.msg);
}
for (const auto &i: TESTS)
tap.expect_throw<ipv4::error> ([&] { ipv4::ip::parse (i.str); }, "%s", i.msg);
}

View File

@ -0,0 +1 @@
{ "type": "number", "minimum": -1 }

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