Merge remote-tracking branch 'origin/master'

This commit is contained in:
Danny Robson 2018-01-10 17:19:39 +11:00
commit 9bb2bdbaba
166 changed files with 4490 additions and 2954 deletions

View File

@ -26,11 +26,11 @@ endif()
###############################################################################
RAGEL_TARGET(json-flat json/flat.cpp.rl ${CMAKE_CURRENT_BINARY_DIR}/json/flat.cpp)
RAGEL_TARGET(uri uri.cpp.rl ${CMAKE_CURRENT_BINARY_DIR}/uri.cpp)
RAGEL_TARGET(json-flat json/flat.cpp.rl ${CMAKE_CURRENT_BINARY_DIR}/json/flat.cpp COMPILE_FLAGS -G2)
RAGEL_TARGET(uri uri.cpp.rl ${CMAKE_CURRENT_BINARY_DIR}/uri.cpp COMPILE_FLAGS -G2)
RAGEL_TARGET(version version.cpp.rl ${CMAKE_CURRENT_BINARY_DIR}/version.cpp)
RAGEL_TARGET(format.cpp format.cpp.rl ${CMAKE_CURRENT_BINARY_DIR}/format.cpp)
RAGEL_TARGET(parse8601 time/parse8601.cpp.rl ${CMAKE_CURRENT_BINARY_DIR}/time/parse8601.cpp)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
@ -76,16 +76,6 @@ else ()
endif ()
###############################################################################
# platform libraries
search_libs (SHM_LIBS shm_open rt)
search_libs (DL_LIBS dlopen dl)
search_libs (CLOCK_LIB clock_gettime rt c)
search_libs (MATH_LIB cos m)
list (APPEND LIBS ${SHM_LIBS} ${DL_LIBS} ${CLOCK_LIB} ${MATH_LIB})
###############################################################################
# platform wrappers
list (
@ -93,8 +83,12 @@ list (
posix/dir.cpp
posix/dir.hpp
posix/dir.ipp
posix/except.cpp
posix/except.hpp
posix/fd.cpp
posix/fd.hpp
posix/socket.cpp
posix/socket.hpp
)
@ -133,6 +127,8 @@ if (WINDOWS)
library_win32.hpp
library_win32.cpp
time_win32.cpp
win32/except.cpp
win32/except.hpp
win32/handle.cpp
win32/handle.hpp
win32/registry.hpp
@ -194,9 +190,9 @@ list (
coord.hpp
coord/init.hpp
coord/iostream.hpp
coord/names.hpp
coord/ops.hpp
coord/store.hpp
coord/traits.hpp
crypto/arc4.cpp
crypto/arc4.hpp
crypto/ice.cpp
@ -212,10 +208,10 @@ list (
debug.cpp
debug.hpp
debug.ipp
encode/base.cpp
encode/base.hpp
endian.cpp
endian.hpp
except.cpp
except.hpp
exe.hpp
extent.cpp
extent.hpp
@ -341,7 +337,6 @@ list (
matrix3.cpp
matrix4.cpp
matrix.hpp
matrix.ipp
memory/deleter.cpp
memory/deleter.hpp
nocopy.hpp
@ -406,7 +401,8 @@ list (
term.hpp
time.cpp
time.hpp
time.ipp
time/parse.hpp
time/parse8601.cpp
tuple.cpp
tuple.hpp
typeidx.cpp
@ -453,7 +449,20 @@ DEPENDS
###############################################################################
add_library(cruft-util ${UTIL_FILES})
target_link_libraries (cruft-util ${LIBS})
target_link_libraries (cruft-util PUBLIC ${LIBS})
target_include_directories(cruft-util PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
###############################################################################
# platform libraries
search_libs (SHM_LIBS shm_open rt)
search_libs (DL_LIBS dlopen dl)
search_libs (CLOCK_LIBS clock_gettime rt c)
search_libs (MATH_LIBS cos m)
target_link_libraries(cruft-util PUBLIC ${SHM_LIBS})
target_link_libraries(cruft-util PUBLIC ${DL_LIBS})
target_link_libraries(cruft-util PUBLIC ${CLOCK_LIBS})
target_link_libraries(cruft-util PUBLIC ${MATH_LIBS})
###############################################################################
@ -461,6 +470,7 @@ foreach (tool hash json-clean json-schema json-validate scratch)
add_executable (util_${tool} tools/${tool}.cpp)
set_target_properties (util_${tool} PROPERTIES OUTPUT_NAME ${tool})
target_link_libraries (util_${tool} cruft-util)
target_include_directories(util_${tool} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
endforeach ()
@ -494,6 +504,7 @@ if (TESTS)
crypto/tea
crypto/xtea
crypto/xxtea
encode/base
endian
exe
extent
@ -542,8 +553,9 @@ if (TESTS)
string
stringid
strongdef
tuple
time/8601
traits
tuple
typeidx
uri
utf8
@ -556,6 +568,7 @@ if (TESTS)
string(REPLACE "/" "_" name "test/${t}")
add_executable(util_${name} test/${t}.cpp)
target_link_libraries(util_${name} PRIVATE cruft-util)
target_include_directories(util_${name} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
add_test(NAME util_${name} COMMAND util_${name})
endforeach(t)
endif ()

67
abnf.rl Normal file
View File

@ -0,0 +1,67 @@
void foo (void) { }
%%{
machine rfc5234;
###############################################################################
# RFC5234 ABNF core rules
# ; A-Z / a-z
ALPHA = 0x41..0x5A | 0x61..0x7A;
BIT = '0' | '1';
# any 7-bit US-ASCII character, excluding NUL
CHAR = 0x01..0x7F;
# carriage return
CR = 0x0D;
# linefeed
LF = 0x0A;
# Internet standard newline
CRLF = CR LF;
# controls
CTL = 0x00..0x1F | 0x7F;
# 0-9
DIGIT = 0x30..0x39;
# " (Double Quote)
DQUOTE = 0x22;
HEXDIG = DIGIT | 'A'..'F';
# horizontal tab
HTAB = 0x09;
SP = 0x20;
# white space
WSP = SP | HTAB;
# Use of this linear-white-space rule permits lines containing only white space
# that are no longer legal in mail headers and have caused interoperability
# problems in other contexts.
#
# Do not use when defining mail headers and use with caution in other contexts.
LWSP = (WSP | CRLF WSP)*;
# 8 bits of data
OCTET = any; #0x00..0xFF;
# visible (printing) characters
VCHAR = 0x21..0x7E;
write data;
}%%
int main () {
%%write init;
%%write exec;
}

View File

@ -44,6 +44,6 @@ namespace cruft::util::sort {
soa (RandomIt key_first, RandomIt key_last, Comparator comp, Args ...values);
}
#include "./sort.ipp"
#include "sort.ipp"
#endif

View File

@ -1 +1 @@
#include "./allocator.hpp"
#include "allocator.hpp"

View File

@ -38,6 +38,6 @@ namespace util::alloc {
};
}
#include "./allocator.ipp"
#include "allocator.ipp"
#endif

View File

@ -1 +1 @@
#include "./arena.hpp"
#include "arena.hpp"

View File

@ -68,6 +68,6 @@ namespace util::alloc {
};
}
#include "./arena.ipp"
#include "arena.ipp"
#endif

View File

@ -14,7 +14,7 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "./affix.hpp"
#include "affix.hpp"
using util::alloc::raw::affix;

View File

@ -14,7 +14,7 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "./linear.hpp"
#include "linear.hpp"
#include "../../pointer.hpp"
#include "../../debug.hpp"

View File

@ -14,7 +14,7 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "./malloc.hpp"
#include "malloc.hpp"
#include "../../debug.hpp"

View File

@ -15,7 +15,7 @@
*/
#include "./null.hpp"
#include "null.hpp"
#include "../../debug.hpp"

View File

@ -14,7 +14,7 @@
* Copyright 2015-2016 Danny Robson <danny@nerdcruft.net>
*/
#include "./stack.hpp"
#include "stack.hpp"
#include "../../debug.hpp"
#include "../../pointer.hpp"

View File

@ -17,7 +17,7 @@
#ifndef __CRUFT_UTIL_ASCII_HPP
#define __CRUFT_UTIL_ASCII_HPP
#include "./annotation.hpp"
#include "annotation.hpp"
#include <cstdint>
#include <stdexcept>
@ -77,7 +77,7 @@ namespace util::ascii {
//-------------------------------------------------------------------------
constexpr inline
unsigned
uint8_t
from_hex (char c)
{
return c >= '0' && c <= '9' ? (c - '0' ) :

View File

@ -17,10 +17,10 @@
#include "backtrace.hpp"
#include "./debug.hpp"
#include "./exe.hpp"
#include "./io.hpp"
#include "./cast.hpp"
#include "debug.hpp"
#include "exe.hpp"
#include "io.hpp"
#include "cast.hpp"
#include <sstream>
#include <cstdio>

View File

@ -14,11 +14,12 @@
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
*/
#include "./backtrace.hpp"
#include "backtrace.hpp"
#include "./debug.hpp"
#include "./except.hpp"
#include "./types.hpp"
#include "debug.hpp"
#include "except.hpp"
#include "types.hpp"
#include "win32/error.hpp"
#include <windows.h>
#include <dbghelp.h>
@ -66,7 +67,7 @@ backtrace::backtrace ()
SymGetModuleBase64,
nullptr))
{
util::win32_error::throw_code ();
util::win32::error::throw_code ();
}
// we've read the bottom of the stack

View File

@ -15,11 +15,12 @@
* 2012-2016, Danny Robson <danny@nerdcruft.net>
*/
#include "./backtrace.hpp"
#include "backtrace.hpp"
#include "./win32/handle.hpp"
#include "./debug.hpp"
#include "./except.hpp"
#include "win32/error.hpp"
#include "win32/handle.hpp"
#include "debug.hpp"
#include "except.hpp"
#include <cstdlib>
#include <windows.h>
@ -33,7 +34,7 @@ debug::backtrace::backtrace (void)
auto process = GetCurrentProcess();
if (!SymInitialize (process, NULL, TRUE))
util::win32_error::throw_code ();
util::win32::error::throw_code ();
while (true) {
auto res = CaptureStackBackTrace (1, m_frames.size (), m_frames.data (), NULL);

View File

@ -14,12 +14,12 @@
* Copyright 2015-2016 Danny Robson <danny@nerdcruft.net>
*/
#include "./bezier.hpp"
#include "bezier.hpp"
#include "./debug.hpp"
#include "./polynomial.hpp"
#include "./stream.hpp"
#include "./coord/iostream.hpp"
#include "debug.hpp"
#include "polynomial.hpp"
#include "stream.hpp"
#include "coord/iostream.hpp"
#include <algorithm>
#include <iterator>

View File

@ -14,7 +14,7 @@
* Copyright 2015-2016 Danny Robson <danny@nerdcruft.net>
*/
#include "./bezier.hpp"
#include "bezier.hpp"
#include <array>
#include <iostream>

View File

@ -14,10 +14,10 @@
* Copyright 2015-2016 Danny Robson <danny@nerdcruft.net>
*/
#include "./bezier.hpp"
#include "bezier.hpp"
#include "./polynomial.hpp"
#include "./coord/iostream.hpp"
#include "polynomial.hpp"
#include "coord/iostream.hpp"
///////////////////////////////////////////////////////////////////////////////

View File

@ -14,7 +14,7 @@
* Copyright 2015-2016 Danny Robson <danny@nerdcruft.net>
*/
#include "./bezier.hpp"
#include "bezier.hpp"
#include "coord/iostream.hpp"
@ -30,10 +30,10 @@ namespace util {
CHECK_GE (t, 0);
CHECK_LE (t, 1);
auto v0 = pow (1 - t, 3) * m_points[0];
auto v0 = pow (1 - t, 3u) * m_points[0];
auto v1 = 3 * pow2 (1 - t) * t * m_points[1];
auto v2 = 3 * pow2 (1 - t) * t * m_points[2];
auto v3 = pow (t, 3) * m_points[3];
auto v3 = pow (t, 3u) * m_points[3];
return {
v0.x + v1.x + v2.x + v3.x,

View File

@ -17,7 +17,7 @@
#ifndef __UTIL_CAST_HPP
#define __UTIL_CAST_HPP
#include "./debug.hpp"
#include "debug.hpp"
#include <type_traits>
#include <limits>

View File

@ -14,10 +14,10 @@
* Copyright 2013-2016 Danny Robson <danny@nerdcruft.net>
*/
#include "./cmdopt.hpp"
#include "cmdopt.hpp"
#include "./cast.hpp"
#include "./debug.hpp"
#include "cast.hpp"
#include "debug.hpp"
#include <cstring>
#include <iostream>
@ -192,27 +192,27 @@ suffix_to_multiplier (char c)
switch (c) {
case 'e':
case 'E':
return util::pow (1024UL, 6);
return util::pow (1024UL, 6u);
case 'p':
case 'P':
return util::pow (1024UL, 5);
return util::pow (1024UL, 5u);
case 't':
case 'T':
return util::pow (1024UL, 4);
return util::pow (1024UL, 4u);
case 'g':
case 'G':
return util::pow (1024UL, 3);
return util::pow (1024UL, 3u);
case 'm':
case 'M':
return util::pow (1024UL, 2);
return util::pow (1024UL, 2u);
case 'k':
case 'K':
return util::pow (1024UL, 1);
return util::pow (1024UL, 1u);
default:
const char str[2] = { c, '\0' };

View File

@ -23,8 +23,8 @@
#include <iterator>
#include <sstream>
#include "./introspection.hpp"
#include "./iterator.hpp"
#include "introspection.hpp"
#include "iterator.hpp"
namespace util::cmdopt {
///////////////////////////////////////////////////////////////////////////

View File

@ -14,454 +14,45 @@
* Copyright 2010-2017 Danny Robson <danny@nerdcruft.net>
*/
#include "./colour.hpp"
#include "colour.hpp"
#include "./ascii.hpp"
#include "./debug.hpp"
#include "./log.hpp"
#include "./range.hpp"
#include <array>
#include <map>
///////////////////////////////////////////////////////////////////////////////
using util::colour;
using util::colour3f;
using util::colour4f;
#include "ascii.hpp"
#include "parse.hpp"
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
colour<S,T>
colour<S,T>::parse_html (const char *fmt)
static util::srgba4f
parse_hex (util::view<const char*> str)
{
// ensure the format is the correct length
auto len = strlen (fmt);
if (str.size () != strlen ("#012345"))
throw std::invalid_argument ("expected length of 7");
switch (len) {
case 1 + 2 * S:
if (*fmt != '#')
throw std::invalid_argument ("missing leading hash");
++fmt;
break;
if (str[0] != '#')
throw std::invalid_argument ("expected leading '#'");
case 2 * S:
break;
default:
throw std::invalid_argument ("format is the wrong length");
if (!util::ascii::is_hex (str[1]) ||
!util::ascii::is_hex (str[2]) ||
!util::ascii::is_hex (str[3]) ||
!util::ascii::is_hex (str[4]) ||
!util::ascii::is_hex (str[5]) ||
!util::ascii::is_hex (str[6]))
{
throw std::invalid_argument ("expected hex digits");
}
// parse the octets
util::colour<S,uint8_t> res;
for (size_t i = 0; i < res.size (); ++i) {
auto a = util::ascii::from_hex (fmt[i*2+0]);
auto b = util::ascii::from_hex (fmt[i*2+1]);
uint8_t r = util::ascii::from_hex (str[1]) << 4u | util::ascii::from_hex (str[2]);
uint8_t g = util::ascii::from_hex (str[3]) << 4u | util::ascii::from_hex (str[4]);
uint8_t b = util::ascii::from_hex (str[5]) << 4u | util::ascii::from_hex (str[6]);
res[i] = (a << 4u) | b;
}
return res.template cast<T> ();
return util::srgba<4,uint8_t> { r, g, b, 255 }.template cast<float> ();
}
///////////////////////////////////////////////////////////////////////////////
static const std::map<std::string, colour<4,uint8_t>>
HTML_COLOURS { {
{ "white", { 0xff, 0xff, 0xff, 0xff } },
{ "silver", { 0xc0, 0xc0, 0xc0, 0xff } },
{ "gray", { 0x80, 0x80, 0x80, 0xff } },
{ "black", { 0x00, 0x00, 0x00, 0xff } },
{ "red", { 0xff, 0x00, 0x00, 0xff } },
{ "maroon", { 0x80, 0x00, 0x00, 0xff } },
{ "yellow", { 0xff, 0xff, 0x00, 0xff } },
{ "olive", { 0x80, 0x80, 0x00, 0xff } },
{ "lime", { 0x00, 0xff, 0x00, 0xff } },
{ "green", { 0x00, 0x80, 0x00, 0xff } },
{ "aqua", { 0x00, 0xff, 0xff, 0xff } },
{ "teal", { 0x00, 0x80, 0x80, 0xff } },
{ "blue", { 0x00, 0x00, 0xff, 0xff } },
{ "navy", { 0x00, 0x00, 0x80, 0xff } },
{ "fuchsia", { 0xff, 0x00, 0xff, 0xff } },
{ "purple", { 0x80, 0x00, 0x80, 0xff } },
} };
//-----------------------------------------------------------------------------
static const std::map<std::string, colour<4,uint8_t>> X11_COLOURS
template <>
util::srgba4f
util::parse<util::srgba4f> (util::view<const char*> str)
{
/* pink */
{ "pink", { 0xff, 0xc0, 0xcb, 0xff } },
{ "lightpink", { 0xff, 0xb6, 0xc1, 0xff } },
{ "hotpink", { 0xff, 0x69, 0xb4, 0xff } },
{ "deeppink", { 0xff, 0x14, 0x93, 0xff } },
{ "palevioletred", { 0xdb, 0x70, 0x93, 0xff } },
{ "mediumvioletred", { 0xc7, 0x15, 0x85, 0xff } },
/* red */
{ "lightsalmon", { 0xff, 0xa0, 0x7a, 0xff } },
{ "salmon", { 0xfa, 0x80, 0x72, 0xff } },
{ "darksalmon", { 0xe9, 0x96, 0x7a, 0xff } },
{ "lightcoral", { 0xf0, 0x80, 0x80, 0xff } },
{ "indianred", { 0xcd, 0x5c, 0x5c, 0xff } },
{ "crimson", { 0xdc, 0x14, 0x3c, 0xff } },
{ "firebrick", { 0xb2, 0x22, 0x22, 0xff } },
{ "darkred", { 0x8b, 0x00, 0x00, 0xff } },
{ "red", { 0xff, 0x00, 0x00, 0xff } },
/* orange */
{ "orangered", { 0xff, 0x45, 0x00, 0xff } },
{ "tomato", { 0xff, 0x63, 0x47, 0xff } },
{ "coral", { 0xff, 0x7f, 0x50, 0xff } },
{ "darkorange", { 0xff, 0x8c, 0x00, 0xff } },
{ "orange", { 0xff, 0xa5, 0x00, 0xff } },
/* yellow */
{ "yellow", { 0xff, 0xff, 0x00, 0xff } },
{ "lightyellow", { 0xff, 0xff, 0xe0, 0xff } },
{ "lemonchiffon", { 0xff, 0xfa, 0xcd, 0xff } },
{ "lightgoldenrodyellow", { 0xfa, 0xfa, 0xd2, 0xff } },
{ "papayawhip", { 0xff, 0xef, 0xd5, 0xff } },
{ "moccasin", { 0xff, 0xe4, 0xb5, 0xff } },
{ "peachpuff", { 0xff, 0xda, 0xb9, 0xff } },
{ "palegoldenrod", { 0xee, 0xe8, 0xaa, 0xff } },
{ "khaki", { 0xf0, 0xe6, 0x8c, 0xff } },
{ "darkkhaki", { 0xbd, 0xb7, 0x6b, 0xff } },
{ "gold", { 0xff, 0xd7, 0x00, 0xff } },
/* brown */
{ "cornsilk", { 0xff, 0xf8, 0xdc, 0xff } },
{ "blanchedalmond", { 0xff, 0xeb, 0xcd, 0xff } },
{ "bisque", { 0xff, 0xe4, 0xc4, 0xff } },
{ "navajowhite", { 0xff, 0xde, 0xad, 0xff } },
{ "wheat", { 0xf5, 0xde, 0xb3, 0xff } },
{ "burlywood", { 0xde, 0xb8, 0x87, 0xff } },
{ "tan", { 0xd2, 0xb4, 0x8c, 0xff } },
{ "rosybrown", { 0xbc, 0x8f, 0x8f, 0xff } },
{ "sandybrown", { 0xf4, 0xa4, 0x60, 0xff } },
{ "goldenrod", { 0xda, 0xa5, 0x20, 0xff } },
{ "darkgoldenrod", { 0xb8, 0x86, 0x0b, 0xff } },
{ "peru", { 0xcd, 0x85, 0x3f, 0xff } },
{ "chocolate", { 0xd2, 0x69, 0x1e, 0xff } },
{ "saddlebrown", { 0x8b, 0x45, 0x13, 0xff } },
{ "sienna", { 0xa0, 0x52, 0x2d, 0xff } },
{ "brown", { 0xa5, 0x2a, 0x2a, 0xff } },
{ "maroon", { 0x80, 0x00, 0x00, 0xff } },
/* green */
{ "darkolivegreen", { 0x55, 0x6b, 0x2f, 0xff } },
{ "olive", { 0x80, 0x80, 0x00, 0xff } },
{ "olivedrab", { 0x6b, 0x8e, 0x23, 0xff } },
{ "yellowgreen", { 0x9a, 0xcd, 0x32, 0xff } },
{ "limegreen", { 0x32, 0xcd, 0x32, 0xff } },
{ "lime", { 0x00, 0xff, 0x00, 0xff } },
{ "lawngreen", { 0x7c, 0xfc, 0x00, 0xff } },
{ "chartreuse", { 0x7f, 0xff, 0x00, 0xff } },
{ "greenyellow", { 0xad, 0xff, 0x2f, 0xff } },
{ "springgreen", { 0x00, 0xff, 0x7f, 0xff } },
{ "mediumspringgreen", { 0x00, 0xfa, 0x9a, 0xff } },
{ "lightgreen", { 0x90, 0xee, 0x90, 0xff } },
{ "palegreen", { 0x98, 0xfb, 0x98, 0xff } },
{ "darkseagreen", { 0x8f, 0xbc, 0x8f, 0xff } },
{ "mediumseagreen", { 0x3c, 0xb3, 0x71, 0xff } },
{ "seagreen", { 0x2e, 0x8b, 0x57, 0xff } },
{ "forestgreen", { 0x22, 0x8b, 0x22, 0xff } },
{ "green", { 0x00, 0x80, 0x00, 0xff } },
{ "darkgreen", { 0x00, 0x64, 0x00, 0xff } },
/* cyan */
{ "mediumaquamarine", { 0x66, 0xcd, 0xaa, 0xff } },
{ "aqua", { 0x00, 0xff, 0xff, 0xff } },
{ "cyan", { 0x00, 0xff, 0xff, 0xff } },
{ "lightcyan", { 0xe0, 0xff, 0xff, 0xff } },
{ "paleturquoise", { 0xaf, 0xee, 0xee, 0xff } },
{ "aquamarine", { 0x7f, 0xff, 0xd4, 0xff } },
{ "turquoise", { 0x40, 0xe0, 0xd0, 0xff } },
{ "mediumturquoise", { 0x48, 0xd1, 0xcc, 0xff } },
{ "darkturquoise", { 0x00, 0xce, 0xd1, 0xff } },
{ "lightseagreen", { 0x20, 0xb2, 0xaa, 0xff } },
{ "cadetblue", { 0x5f, 0x9e, 0xa0, 0xff } },
{ "darkcyan", { 0x00, 0x8b, 0x8b, 0xff } },
{ "teal", { 0x00, 0x80, 0x80, 0xff } },
/* blue */
{ "lightsteelblue", { 0xb0, 0xc4, 0xde, 0xff } },
{ "powderblue", { 0xb0, 0xe0, 0xe6, 0xff } },
{ "lightblue", { 0xad, 0xd8, 0xe6, 0xff } },
{ "skyblue", { 0x87, 0xce, 0xeb, 0xff } },
{ "lightskyblue", { 0x87, 0xce, 0xfa, 0xff } },
{ "deepskyblue", { 0x00, 0xbf, 0xff, 0xff } },
{ "dodgerblue", { 0x1e, 0x90, 0xff, 0xff } },
{ "cornflowerblue", { 0x64, 0x95, 0xed, 0xff } },
{ "steelblue", { 0x46, 0x82, 0xb4, 0xff } },
{ "royalblue", { 0x41, 0x69, 0xe1, 0xff } },
{ "blue", { 0x00, 0x00, 0xff, 0xff } },
{ "mediumblue", { 0x00, 0x00, 0xcd, 0xff } },
{ "darkblue", { 0x00, 0x00, 0x8b, 0xff } },
{ "navy", { 0x00, 0x00, 0x80, 0xff } },
{ "midnightblue", { 0x19, 0x19, 0x70, 0xff } },
/* purple */
{ "lavender", { 0xe6, 0xe6, 0xfa, 0xff } },
{ "thistle", { 0xd8, 0xbf, 0xd8, 0xff } },
{ "plum", { 0xdd, 0xa0, 0xdd, 0xff } },
{ "violet", { 0xee, 0x82, 0xee, 0xff } },
{ "orchid", { 0xda, 0x70, 0xd6, 0xff } },
{ "fuchsia", { 0xff, 0x00, 0xff, 0xff } },
{ "magenta", { 0xff, 0x00, 0xff, 0xff } },
{ "mediumorchid", { 0xba, 0x55, 0xd3, 0xff } },
{ "mediumpurple", { 0x93, 0x70, 0xdb, 0xff } },
{ "blueviolet", { 0x8a, 0x2b, 0xe2, 0xff } },
{ "darkviolet", { 0x94, 0x00, 0xd3, 0xff } },
{ "darkorchid", { 0x99, 0x32, 0xcc, 0xff } },
{ "darkmagenta", { 0x8b, 0x00, 0x8b, 0xff } },
{ "purple", { 0x80, 0x00, 0x80, 0xff } },
{ "indigo", { 0x4b, 0x00, 0x82, 0xff } },
{ "darkslateblue", { 0x48, 0x3d, 0x8b, 0xff } },
{ "rebeccapurple", { 0x66, 0x33, 0x99, 0xff } },
{ "slateblue", { 0x6a, 0x5a, 0xcd, 0xff } },
{ "mediumslateblue", { 0x7b, 0x68, 0xee, 0xff } },
/* white */
{ "white", { 0xff, 0xff, 0xff, 0xff } },
{ "snow", { 0xff, 0xfa, 0xfa, 0xff } },
{ "honeydew", { 0xf0, 0xff, 0xf0, 0xff } },
{ "mintcream", { 0xf5, 0xff, 0xfa, 0xff } },
{ "azure", { 0xf0, 0xff, 0xff, 0xff } },
{ "aliceblue", { 0xf0, 0xf8, 0xff, 0xff } },
{ "ghostwhite", { 0xf8, 0xf8, 0xff, 0xff } },
{ "whitesmoke", { 0xf5, 0xf5, 0xf5, 0xff } },
{ "seashell", { 0xff, 0xf5, 0xee, 0xff } },
{ "beige", { 0xf5, 0xf5, 0xdc, 0xff } },
{ "oldlace", { 0xfd, 0xf5, 0xe6, 0xff } },
{ "floralwhite", { 0xff, 0xfa, 0xf0, 0xff } },
{ "ivory", { 0xff, 0xff, 0xf0, 0xff } },
{ "antiquewhite", { 0xfa, 0xeb, 0xd7, 0xff } },
{ "linen", { 0xfa, 0xf0, 0xe6, 0xff } },
{ "lavenderblush", { 0xff, 0xf0, 0xf5, 0xff } },
{ "mistyrose", { 0xff, 0xe4, 0xe1, 0xff } },
/* grey/black */
{ "gainsboro", { 0xdc, 0xdc, 0xdc, 0xff } },
{ "lightgrey", { 0xd3, 0xd3, 0xd3, 0xff } },
{ "silver", { 0xc0, 0xc0, 0xc0, 0xff } },
{ "darkgray", { 0xa9, 0xa9, 0xa9, 0xff } },
{ "gray", { 0x80, 0x80, 0x80, 0xff } },
{ "dimgray", { 0x69, 0x69, 0x69, 0xff } },
{ "lightslategray", { 0x77, 0x88, 0x99, 0xff } },
{ "slategray", { 0x70, 0x80, 0x90, 0xff } },
{ "darkslategray", { 0x2f, 0x4f, 0x4f, 0xff } },
{ "black", { 0x00, 0x00, 0x00, 0xff } },
};
//-----------------------------------------------------------------------------
template <size_t S, typename T>
static colour<S,T>
lookup_colour (const std::string &name,
const std::map<std::string,colour<4,uint8_t>> &map)
{
std::string lower (name);
std::transform (lower.begin (), lower.end (), lower.begin (), tolower);
auto pos = map.find (lower);
if (pos == map.end ())
throw std::out_of_range (name);
static_assert (S <= 4, "cannot invent additional data");
return pos->second.template redim<S> ().template cast<T> ();
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
colour<S,T>
colour<S,T>::from_html (const std::string &name)
{
return lookup_colour<S,T> (name, HTML_COLOURS);
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
colour<S,T>
colour<S,T>::from_x11 (const std::string &name)
{
return lookup_colour<S,T> (name, X11_COLOURS);
}
///////////////////////////////////////////////////////////////////////////////
colour3f
util::rgb_to_hsv (colour3f rgb)
{
// Calculate chroma
auto M = max (rgb);
auto m = min (rgb);
auto C = M - m;
// Undefined for zero chroma
if (almost_zero (C))
return { -1.f, 0.f, M };
// Calculate hue
float H = exactly_equal (rgb.r, M) ? (rgb.g - rgb.b) :
exactly_equal (rgb.g, M) ? 2 + (rgb.b - rgb.r) :
exactly_equal (rgb.b, M) ? 4 + (rgb.r - rgb.g) :
0 ;
H /= C;
H *= 60;
if (H < 0)
H += 360;
// Calculate value
auto V = M;
// Calculate saturation
auto S = almost_zero (V) ? 0.f : C / V;
return { H, S, V };
}
//-----------------------------------------------------------------------------
colour3f
util::hsv_to_rgb (colour3f hsv)
{
CHECK_GE (hsv.h, 0);
CHECK_LT (hsv.h, 360);
CHECK_GE (hsv.s, 0);
CHECK_LE (hsv.s, 1);
CHECK_GE (hsv.v, 0);
CHECK_LE (hsv.v, 1);
float C = hsv.v * hsv.s;
float H = hsv.h / 60;
float X = C * (1 - std::abs (std::fmod (H, 2.f) - 1));
// monochromatic'ish
if (almost_zero (hsv.s))
return colour3f { hsv.v };
colour3f rgb;
unsigned hex = (unsigned)H;
switch (hex) {
case 0: rgb = { C, X, 0 }; break;
case 1: rgb = { X, C, 0 }; break;
case 2: rgb = { 0, C, X }; break;
case 3: rgb = { 0, X, C }; break;
case 4: rgb = { X, 0, C }; break;
case 5: rgb = { C, 0, X }; break;
}
auto m = hsv.v - C;
return rgb + m;
}
///----------------------------------------------------------------------------
/// Extract a colour object from a JSON node.
#include "json/tree.hpp"
namespace json::tree {
template <>
util::colour4f
io<util::colour4f>::deserialise (const node &root) {
return {
root[0].as<float> (),
root[1].as<float> (),
root[2].as<float> (),
root[3].as<float> (),
};
}
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
std::ostream&
util::operator<< (std::ostream &os, util::colour<S,T> c)
{
return os << "[ " << util::make_infix (util::numeric_view (c), ", ") << ']';
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
std::istream&
util::operator>> (std::istream &is, util::colour<S,T> &c)
{
std::array<
std::conditional_t<
sizeof(T) == 1,
uint16_t,
T
>,S
> v;
static_assert (S > 0, "current implementation requires strictly positive components");
char comma;
for (size_t i = 0; i < S - 1; ++i) {
is >> v[i] >> comma;
if (comma != ',' || is.eof ()) {
is.setstate (std::ios_base::failbit);
return is;
}
}
is >> v[S-1];
if (!std::is_same<T, typename decltype(v)::value_type>::value) {
if (std::any_of (std::cbegin (v),
std::cend (v),
[] (auto i) {
return i > std::numeric_limits<T>::max ();
})) {
is.setstate (std::ios_base::failbit);
return is;
}
}
std::copy (std::cbegin (v),
std::cend (v),
std::begin (c));
return is;
}
//-----------------------------------------------------------------------------
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>); \
\
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,uint16_t) \
INSTANTIATE_S_T(S,float) \
INSTANTIATE_S_T(S,double)
//-----------------------------------------------------------------------------
INSTANTIATE_S(1)
INSTANTIATE_S(3)
INSTANTIATE_S(4)
return parse_hex (str);
}

View File

@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2010-2015 Danny Robson <danny@nerdcruft.net>
* Copyright 2010-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_COLOUR_HPP
@ -21,68 +21,98 @@
#include "introspection.hpp"
#include <ostream>
#include <type_traits>
namespace util {
/// An RGBA colour POD type.
template <size_t S, typename T>
struct colour : public coord::base<S,T,colour,coord::rgba,coord::hsv> {
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>;
/// An abstract colour POD type componsed of S components of type T.
///
/// Not to be used directly, instead the use of derived types is required.
/// This exists purely to simplify generic colour code.
template <
size_t S,
typename T,
typename SelfT
>
struct colour : coord::base<S,T,SelfT> {
using coord::base<S,T,SelfT>::base;
// overloaded cast operator which assumes values are unit normalised
template <typename U>
colour<S,U>
cast (void) const;
/// parse colours specified as "#AABBCCDD".
///
/// * the leading hash is optional.
/// * all components must be 2 hex digits.
static colour parse_html (const char*);
static colour parse_html (const std::string&);
/// look up the name of a colour from those specified in
/// html/x11/etc specifications.
static colour from_html (const std::string &name);
static colour from_x11 (const std::string &name);
/// look up all the specifications and returns the colour from one
/// that matches. the search order is unspecified, so if you want a
/// known colour then try them first yourself.
static colour from_string (const std::string &name);
auto
cast (void) const
{
::util::revalue_t<SelfT,U> ret;
std::transform (std::begin (*this),
std::end (*this),
std::begin (ret),
renormalise<T,U>);
return ret;
}
};
// Convenience types
template <typename T> using colour1 = colour<1,T>;
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;
typedef colour1<float> colour1f;
typedef colour3<float> colour3f;
typedef colour4<float> colour4f;
// 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>);
template <size_t S, typename 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";
template <typename T>
struct util::coord::store<1,T,srgba<1,T>> {
union { struct { T r; }; T data[1]; };
};
template <typename T>
struct util::coord::store<2,T,srgba<2,T>> {
union { struct { T r, g; }; T data[2]; };
};
template <typename T>
struct util::coord::store<3,T,srgba<3,T>> {
union { struct { T r, g, b; }; T data[3]; };
};
template <typename T>
struct util::coord::store<4,T,srgba<4,T>> {
union { struct { T r, g, b, a; }; T data[4]; };
};
template <size_t S, typename T> struct srgba : colour<S,T,srgba<S,T>> {
using colour<S,T,srgba<S,T>>::colour;
};
using srgba3f = srgba<3,float>;
using srgba4f = srgba<4,float>;
using srgba3u = srgba<3,uint8_t>;
using srgba4u = srgba<4,uint8_t>;
template <size_t S, typename T> struct hsva : colour<S,T,hsva<S,T>> {};
template <size_t S, typename T>
struct redim_type<
srgba<S,T>
> { template <size_t _S> using type = srgba<_S,T>; };
template <size_t S, typename T>
struct revalue_type<srgba<S,T>> {
template <typename _T>
using type = srgba<S,_T>;
};
template <typename> struct is_colour : public std::false_type {};
template <
size_t S,
typename T,
template <
size_t,
typename
> typename ColourT
> struct is_colour<ColourT<S,T>>
:std::conditional_t<
std::is_base_of_v<
colour<S,T,ColourT<S,T>>,
ColourT<S,T>
>,
std::true_type,
std::false_type
> {};
template <typename T>
constexpr auto is_colour_v = is_colour<T>::value;
}
#include "colour.ipp"

View File

@ -19,15 +19,3 @@
#endif
#define __UTIL_COLOUR_IPP
template <size_t S, typename T>
template <typename U>
util::colour<S,U>
util::colour<S,T>::cast (void) const
{
colour<S,U> ret;
std::transform (this->begin (),
this->end (),
ret.begin (),
renormalise<T,U>);
return ret;
}

View File

@ -17,36 +17,46 @@
#ifndef CRUFT_UTIL_COORD_BASE_HPP
#define CRUFT_UTIL_COORD_BASE_HPP
#include "init.hpp"
#include "fwd.hpp"
#include "./ops.hpp"
#include "ops.hpp"
#include "init.hpp"
#include "traits.hpp"
#include "../maths.hpp"
#include <algorithm>
#include <cstdlib>
#include <type_traits>
namespace util::coord {
/////////////////////////////////////////////////////////////////////////
// the base class for all coordinate-like types.
//
// SelfT should not be exposed as a template template directly because
// some types (eg, XYZ colours) do not conform to the same template
// parameters are others (eg, vector2f). ie, it does not make sense to
// allow redim, or type changing on some types so they just aren't exposed.
template <
std::size_t S,
typename T,
template <std::size_t, typename> class KLASS,
typename ...tags
typename SelfT
>
struct base : public init<S,T,tags...> {
struct base : public init<S,T,SelfT> {
static_assert (S > 0);
static_assert (std::is_arithmetic<T>::value);
static_assert (sizeof (init<S,T,SelfT>) == S * sizeof (T));
using self_t = SelfT;
using value_type = T;
static constexpr std::size_t dimension = S;
static constexpr std::size_t elements = S;
/// returns the number of elements we contain
static constexpr std::size_t size (void) { return S; }
static constexpr auto size (void) { return S; }
// inherit the fancy elementwise constructors from `init'.
using init<S,T,tags...>::init;
// constructors
using init<S,T,SelfT>::init;
/// constructs, but does not initialise, the data.
///
@ -63,12 +73,21 @@ namespace util::coord {
this->data[i] = fill;
}
constexpr base (const base<S,T,KLASS,tags...> &rhs) = default;
base& operator= (const base<S,T,KLASS,tags...> &rhs) = default;
constexpr base (const base<S,T,SelfT> &rhs) = default;
base& operator= (const base<S,T,SelfT> &rhs)& = default;
base& operator= (const T t)&
{
for (auto v: *this)
v = t;
return *this;
}
// element accessors
T& operator[] (std::size_t i) { return this->data[i]; }
constexpr const T& operator[] (std::size_t i) const { return this->data[i]; }
constexpr T& operator[] (size_t i)& noexcept { return this->data[i]; }
constexpr T& operator[] (int i)& noexcept { return this->data[i]; }
constexpr const T& operator[] (size_t i) const& noexcept { return this->data[i]; }
constexpr const T& operator[] (int i) const& noexcept { return this->data[i]; }
auto cbegin (void) const { return std::cbegin (this->data); }
auto cend (void) const { return std::cend (this->data); }
@ -95,12 +114,28 @@ namespace util::coord {
return k;
}
//---------------------------------------------------------------------
template <
typename K,
typename = std::enable_if_t<is_coord_v<K>,void>
>
K as (void) const
{
static_assert (K::elements == elements);
K k;
std::copy (begin (), end (), k.begin ());
return k;
}
//---------------------------------
template <typename U>
KLASS<S,U>
auto
cast (void) const
{
KLASS<S,U> out;
typename revalue_type<SelfT>::template type<U> out;
std::copy (std::cbegin (this->data),
std::cend (this->data),
std::begin (out.data));
@ -113,14 +148,21 @@ namespace util::coord {
///
/// explicitly does not allow a fill parameter given it can't be used
/// when reducing dimensions.
template <std::size_t D>
template <
size_t D,
typename _sfinae = SelfT
>
std::enable_if_t<
D <= S, KLASS<D,T>
has_redim_v<_sfinae>,
redim_t<_sfinae,D>
>
redim (void) const
{
KLASS<D,T> out;
std::copy_n (cbegin (), D, std::begin (out.data));
redim_t<SelfT,D> out;
std::copy_n (std::cbegin (this->data),
min (S, D),
std::begin (out.data));
return out;
}
@ -132,13 +174,14 @@ namespace util::coord {
///
/// explicitly requires a fill parameter so that we avoid undefined
/// values.
template <std::size_t D>
template<size_t D,typename _sfinae = SelfT>
std::enable_if_t<
(D > S), KLASS<D,T>
has_redim_v<_sfinae>,
redim_t<_sfinae,D>
>
redim (const KLASS<D,T> fill) const
redim (const redim_t<_sfinae,D> fill) const
{
KLASS<D,T> out;
redim_t<SelfT,D> out;
auto next = std::copy (cbegin (), cend (), std::begin (out));
std::copy (std::cbegin (fill) + S, std::cend (fill), next);
@ -151,13 +194,17 @@ namespace util::coord {
///
/// explicitly requires a fill parameter so that we avoid undefined
/// values.
template <std::size_t D>
template <
size_t D,
typename _sfinae = SelfT
>
std::enable_if_t<
(D > S), KLASS<D,T>
has_redim_v<_sfinae>,
redim_t<_sfinae,D>
>
redim (T fill) const
{
KLASS<D,T> out;
redim_t<SelfT,D> out;
auto next = std::copy (cbegin (), cend (), std::begin (out));
std::fill (next, std::end (out), fill);
@ -172,7 +219,7 @@ namespace util::coord {
/// it's ugly as sin, but simplifies some situations where we don't
/// want a temporary.
template <std::size_t ...Indices>
KLASS<sizeof...(Indices),T>
constexpr auto
indices (void) const
{
static_assert (
@ -180,11 +227,11 @@ namespace util::coord {
"indices must fall within the defined range for the type"
);
return KLASS<sizeof...(Indices),T> { this->data[Indices]... };
return redim_t<SelfT,sizeof...(Indices)> {
this->data[Indices]...
};
}
};
}
#include "../vector.hpp"
#endif

View File

@ -20,10 +20,17 @@
#include <cstddef>
namespace util {
template <std::size_t,typename> struct colour;
template <std::size_t,typename> struct extent;
template <std::size_t,typename> struct point;
template <std::size_t,typename> struct vector;
namespace coord {
template <size_t S,typename T,typename ParentT> struct store;
template <size_t,typename,typename> struct init;
template <size_t,typename,typename> struct base;
}
template <size_t,typename> struct srgba;
template <size_t,typename> struct hsva;
template <size_t,typename> struct extent;
template <size_t,typename> struct point;
template <size_t,typename> struct vector;
}
#endif

View File

@ -22,53 +22,53 @@
#include <cstddef>
namespace util::coord {
template <std::size_t S, typename T, typename...>
template <size_t S, typename T, typename SelfT>
struct init;
//-------------------------------------------------------------------------
template <typename T, typename ...tags>
struct init<1,T,tags...> : public store<1,T,tags...>
template <typename T, typename SelfT>
struct init<1,T,SelfT> : public store<1,T,SelfT>
{
using store<1,T,tags...>::store;
using store<1,T,SelfT>::store;
constexpr init () = default;
constexpr explicit init (T v0):
store<1,T,tags...> ({v0})
constexpr init (T v0):
store<1,T,SelfT> ({v0})
{ ; }
};
//-------------------------------------------------------------------------
template <typename T, typename ...tags>
struct init<2,T,tags...> : public store<2,T,tags...>
template <typename T, typename SelfT>
struct init<2,T,SelfT> : public store<2,T,SelfT>
{
using store<2,T,tags...>::store;
using store<2,T,SelfT>::store;
constexpr init () = default;
constexpr init (T v0, T v1):
store<2,T,tags...> ({ v0, v1 })
store<2,T,SelfT> ({ v0, v1 })
{ ; }
};
//-------------------------------------------------------------------------
template <typename T, typename ...tags>
struct init<3,T,tags...> : public store<3,T,tags...>
template <typename T, typename SelfT>
struct init<3,T,SelfT> : public store<3,T,SelfT>
{
using store<3,T,tags...>::store;
using store<3,T,SelfT>::store;
constexpr init () = default;
constexpr init (T v0, T v1, T v2):
store<3,T,tags...> ({v0, v1, v2})
store<3,T,SelfT> ({v0, v1, v2})
{ ; }
};
//-------------------------------------------------------------------------
template <typename T, typename ...tags>
struct init<4,T,tags...> : public store<4,T,tags...>
template <typename T, typename SelfT>
struct init<4,T,SelfT> : public store<4,T,SelfT>
{
using store<4,T,tags...>::store;
using store<4,T,SelfT>::store;
constexpr init () = default;
constexpr init (T v0, T v1, T v2, T v3):
store<4,T,tags...> ({ v0, v1, v2, v3 })
store<4,T,SelfT> ({ v0, v1, v2, v3 })
{ ; }
};
}

View File

@ -17,6 +17,7 @@
#ifndef CRUFT_UTIL_IOSTREAM
#define CRUFT_UTIL_IOSTREAM
#include "./traits.hpp"
#include "../iterator.hpp"
#include <cstddef>
@ -25,17 +26,16 @@
namespace util {
template <
template <std::size_t,typename> class K,
std::size_t S,
typename T
typename K,
typename = std::enable_if_t<is_coord_v<K>,void>
>
std::ostream&
operator<< (std::ostream &os, const K<S,T> &k)
operator<< (std::ostream &os, const K &k)
{
os << "[";
std::transform (std::cbegin (k),
std::cend (k),
infix_iterator<T> (os, ", "),
infix_iterator<typename K::value_type> (os, ", "),
[] (auto i) { return +i; });
os << "]";

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -17,11 +17,12 @@
#ifndef CRUFT_UTIL_COORD_STORE_HPP
#define CRUFT_UTIL_COORD_STORE_HPP
#include "names.hpp"
#include "fwd.hpp"
#include "../preprocessor.hpp"
#include "../platform.hpp"
#include <cstdlib>
#include <cstddef>
#include <type_traits>
@ -55,156 +56,112 @@ namespace util::coord::detail {
#define SIMD_ALIGN(S,T) alignas (util::coord::detail::alignment<T> (S))
namespace util::coord {
///////////////////////////////////////////////////////////////////////////
// Coordinate storage class.
//
// Types with trivially suitable arity are aligned appropriately to take
// advantage of native platform SIMD. eg, 4f types are aligned to 16 bytes
// on SSE platforms.
template <
std::size_t S,
typename T,
typename...
>
struct
SIMD_ALIGN(S,T)
store {
T data[S];
};
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct store<3,T,rgba,hsv> {
union {
T data[3];
struct { T r,g,b; };
struct { T h,s,v; };
};
};
// Align on 16 bytes if the data is at least 16 bytes long. Prevents tiny
// types like colour4u requiring massive alignments, reduces internal
// fragmentation.
//
// TODO: expand this for other instruction sets. maybe switch on type.
template <typename T>
struct
SIMD_ALIGN(4,T)
store<4,T,rgba,hsv> {
union {
T data[4];
struct { T r,g,b,a; };
struct { T h,s,v; };
};
};
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct store<2,T,xyzw> {
union {
T data[2];
struct { T x,y; };
};
};
template <typename T>
struct store<3,T,xyzw> {
union {
T data[3];
struct { T x,y,z; };
};
};
// Align on 16 bytes if the data is at least 16 bytes long. Prevents tiny
// types like colour4u requiring massive alignments, reduces internal
// fragmentation.
//
// TODO: expand this for other instruction sets. maybe switch on type.
template <typename T>
struct
SIMD_ALIGN(4,T)
store<4,T,xyzw> {
union {
T data[4];
struct { T x,y,z,w; };
};
};
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct store<2,T,xyzw,stpq> {
union {
T data[2];
struct { T x,y; };
struct { T s,t; };
};
};
template <typename T>
struct store<3,T,xyzw,stpq> {
union {
T data[3];
struct { T x,y,z; };
struct { T s,t,p; };
};
};
// Align on 16 bytes if the data is at least 16 bytes long. Prevents tiny
// types like colour4u requiring massive alignments, reduces internal
// fragmentation.
//
// TODO: expand this for other instruction sets. maybe switch on type.
template <typename T>
struct
SIMD_ALIGN(4,T)
store<4,T,xyzw,stpq> {
union {
T data[4];
struct { T x,y,z,w; };
struct { T s,t,p,q; };
};
};
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct store<2,T,whd> {
union {
T data[2];
struct { T w,h; };
};
};
template <typename T>
struct store<3,T,whd> {
union {
T data[3];
struct { T w,h,d; };
};
};
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct
SIMD_ALIGN(4,T)
store<4,T,wxyz,abcd> {
union {
T data[4];
struct { T w,x,y,z; };
struct { T a,b,c,d; };
};
};
///////////////////////////////////////////////////////////////////////////////
// defines the named member variables that a coordinate type is composed of
#define DEFINE_COORD_STORE(TAG,...) \
namespace util::coord { \
template <typename T> \
struct store< \
VA_ARGS_COUNT(__VA_ARGS__), \
T, \
TAG \
> { \
union { \
struct { \
T __VA_ARGS__; \
}; \
T data[VA_ARGS_COUNT(__VA_ARGS__)]; \
}; \
}; \
}
#define DEFINE_STORE(KLASS,...) \
template <typename T> \
struct util::coord::store< \
VA_ARGS_COUNT(__VA_ARGS__), \
T, \
::util::KLASS< \
VA_ARGS_COUNT(__VA_ARGS__), \
T \
> \
> { \
union { \
T data[VA_ARGS_COUNT(__VA_ARGS__)]; \
struct { T __VA_ARGS__; }; \
}; \
};
DEFINE_STORE(extent,w)
DEFINE_STORE(extent,w,h)
DEFINE_STORE(extent,w,h,d)
DEFINE_STORE(point, x)
DEFINE_STORE(point, x, y)
DEFINE_STORE(point, x, y, z)
DEFINE_STORE(point, x, y, z, w)
DEFINE_STORE(vector, x)
DEFINE_STORE(vector, x, y)
DEFINE_STORE(vector, x, y, z)
DEFINE_STORE(vector, x, y, z, w)
#undef DEFINE_STORE
#if 0
template <typename T>
struct util::coord::store<1,T,::util::extent<1,T>> {
union { T data[1]; struct { T w; }; };
};
template <typename T>
struct util::coord::store<2,T,::util::extent<2,T>> {
union { struct { T w, h; }; T data[2]; };
};
template <typename T>
struct util::coord::store<3,T,::util::extent<3,T>> {
union { struct { T w, h, d; }; T data[3]; };
};
template <typename T>
struct util::coord::store<1,T,::util::point<1,T>> {
union { struct { T x; }; T data[1]; };
};
template <typename T>
struct util::coord::store<2,T,::util::point<2,T>> {
union { struct { T x, y; }; T data[2]; };
};
template <typename T>
struct util::coord::store<3,T,::util::point<3,T>> {
union { struct { T x, y, z; }; T data[3]; };
};
template <typename T>
struct util::coord::store<4,T,::util::point<4,T>> {
union { struct { T x, y, z, w; }; T data[4]; };
};
template <typename T>
struct util::coord::store<1,T,::util::vector<1,T>> {
union { struct { T x; }; T data[1]; };
};
template <typename T>
struct util::coord::store<2,T,::util::vector<2,T>> {
union { struct { T x, y; }; T data[2]; };
};
template <typename T>
struct util::coord::store<3,T,::util::vector<3,T>> {
union { struct { T x, y, z; }; T data[3]; };
};
template <typename T>
struct util::coord::store<4,T,::util::vector<4,T>> {
union { struct { T x, y, z, w; }; T data[4]; };
};
#endif
#endif

225
coord/traits.hpp Normal file
View File

@ -0,0 +1,225 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2012-2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_COORD_TRAITS_HPP
#define CRUFT_UTIL_COORD_TRAITS_HPP
#include "fwd.hpp"
#include <cstddef>
#include <type_traits>
namespace util {
///////////////////////////////////////////////////////////////////////
// operation traits
template <typename, typename>
struct result { };
//-------------------------------------------------------------------------
#define RESULT_T(ArgA,ArgB,ResultT) \
template < \
std::size_t S, \
typename ValueA,\
typename ValueB\
> struct result<\
ArgA<S,ValueA>,\
ArgB<S,ValueB>\
> {\
using type = ResultT<S,std::common_type_t<ValueA,ValueB>>; \
};
#if 0
template <
std::size_t S,
typename ValueA,
typename ValueB
> struct result<
srgba<S,ValueA>,
srgba<S,ValueB>
> {
using type = srgba<S,std::common_type_t<ValueA,ValueB>>;
};
template <std::size_t S, typename T> struct result<srgba<S,T>, vector<S,T>> { using type = srgba<S,T>; };
template <std::size_t S, typename T> struct result<vector<S,T>,srgba<S,T>> { using type = srgba<S,T>; };
template <std::size_t S, typename T> struct result<extent<S,T>,extent<S,T>> { using type = extent<S,T>; };
template <std::size_t S, typename T> struct result<extent<S,T>,vector<S,T>> { using type = extent<S,T>; };
template <std::size_t S, typename T> struct result<point<S,T>, extent<S,T>> { using type = point <S,T>; };
template <std::size_t S, typename T> struct result<point<S,T>, vector<S,T>> { using type = point <S,T>; };
template <std::size_t S, typename T> struct result<vector<S,T>,point<S,T>> { using type = point <S,T>; };
template <std::size_t S, typename T> struct result<vector<S,T>,vector<S,T>> { using type = vector<S,T>; };
#endif
RESULT_T(extent,extent,extent)
RESULT_T(extent,vector,extent)
RESULT_T(point,extent,point)
RESULT_T(point,vector,point)
RESULT_T(srgba,vector,srgba)
RESULT_T(srgba,srgba,srgba)
RESULT_T(vector,point,point)
RESULT_T(vector,srgba,srgba)
RESULT_T(vector,vector,vector)
template <
typename A, typename B
>
using result_t = typename result<A,B>::type;
///////////////////////////////////////////////////////////////////////////
template <typename A, typename B, typename = std::void_t<>>
struct has_result : public std::false_type {};
template <typename CoordA, typename CoordB>
struct has_result<
CoordA,
CoordB,
std::void_t<
result_t<CoordA,CoordB>
>
> : public std::true_type {};
template <typename A, typename B>
constexpr auto has_result_v = has_result<A,B>::value;
//---------------------------------------------------------------------
template <typename>
struct has_norm : public std::false_type { };
template <std::size_t S, typename T> struct has_norm<vector<S,T>> : public std::true_type { };
template <typename T>
constexpr auto has_norm_v = has_norm<T>::value;
//---------------------------------------------------------------------
template <typename T>
struct has_scalar_op : public std::false_type { };
template <std::size_t S, typename T> struct has_scalar_op<srgba<S,T>> : public std::true_type { };
template <std::size_t S, typename T> struct has_scalar_op<extent<S,T>> : public std::true_type { };
template <std::size_t S, typename T> struct has_scalar_op<point<S,T>> : public std::true_type { };
template <std::size_t S, typename T> struct has_scalar_op<vector<S,T>> : public std::true_type { };
template <typename T>
constexpr auto has_scalar_op_v = has_scalar_op<T>::value;
template <class> struct is_coord : std::false_type { };
template <typename T> struct is_coord<const T> : is_coord<T> {};
template <typename T> struct is_coord<T&> : is_coord<T> {};
template <std::size_t S, typename T> struct is_coord<point<S,T>> : std::true_type { };
template <std::size_t S, typename T> struct is_coord<extent<S,T>> : std::true_type { };
template <std::size_t S, typename T> struct is_coord<vector<S,T>> : std::true_type { };
template <std::size_t S, typename T> struct is_coord<srgba<S,T>> : std::true_type { };
template <class K>
constexpr bool
is_coord_v = is_coord<K>::value;
///////////////////////////////////////////////////////////////////////////
template <typename T> struct has_redim : std::false_type {};
//---------------------------------------------------------------------
template <std::size_t S, typename T> struct has_redim< point<S,T>> : public std::true_type {};
template <std::size_t S, typename T> struct has_redim<vector<S,T>> : public std::true_type {};
template <std::size_t S, typename T> struct has_redim<extent<S,T>> : public std::true_type {};
//---------------------------------------------------------------------
template <typename T> constexpr auto has_redim_v = has_redim<T>::value;
///////////////////////////////////////////////////////////////////////////
template <typename> struct redim_type {};
//---------------------------------------------------------------------
template <std::size_t S, typename T> struct redim_type<point<S,T>>
{ template <std::size_t _S> using type = point<_S,T>; };
template <std::size_t S, typename T> struct redim_type<vector<S,T>>
{ template <std::size_t _S> using type = vector<_S,T>; };
template <std::size_t S, typename T> struct redim_type<extent<S,T>>
{ template <std::size_t _S> using type = extent<_S,T>; };
//---------------------------------------------------------------------
template <
typename Self,
std::size_t S
>
using redim_t = typename redim_type<Self>::template type<S>;
///////////////////////////////////////////////////////////////////////////
template <typename> struct revalue_type {};
//-------------------------------------------------------------------------
template <std::size_t S, typename T>
struct revalue_type<point<S,T>> {
template <typename _T> using type = point<S,_T>;
};
template <std::size_t S, typename T>
struct revalue_type<vector<S,T>> {
template <typename _T> using type = vector<S,_T>;
};
template <std::size_t S, typename T>
struct revalue_type<extent<S,T>> {
template <typename _T> using type = extent<S,_T>;
};
//-------------------------------------------------------------------------
template <typename Self, typename T>
using revalue_t = typename revalue_type<Self>::template type<T>;
///////////////////////////////////////////////////////////////////////////
template <typename,typename=void> struct arity {};
template <typename T>
struct arity<T,std::enable_if_t<std::is_arithmetic_v<T>,void>
> :std::integral_constant<std::size_t, 1>
{ };
template <typename T>
struct arity<
T,std::enable_if_t<is_coord_v<T>,void>
> :std::integral_constant<std::size_t,T::elements>
{ };
///////////////////////////////////////////////////////////////////////////
template <typename T>
constexpr auto arity_v = arity<T>::value;
}
#endif

View File

@ -21,7 +21,7 @@
// Software Encryption - Fourth International Workshop, Haifa, Israel,
// Springer-Verlag, pp. 69-82, 1997
#include "./ice.hpp"
#include "ice.hpp"
#include "../endian.hpp"
#include "../debug.hpp"

View File

@ -427,36 +427,72 @@ namespace util::debug {
void init (void);
///////////////////////////////////////////////////////////////////////////
// returns true if an instance of type `T' appears to be in a valid state.
//
// written as a struct rather than a function so that behaviour may be
// arbitrarily specialised. all users are free to specialise this struct
// with an user types.
//
// all specialisations must be safe to call on arbitrary data without
// exceptions or faults as this mechanism is used to control some
// debugging paths which themselves are the configuration points for
// throwing/logging/etc behaviour.
template <typename T>
struct validator {
static bool is_valid (const T&);
static bool is_valid (const T&) noexcept;
};
//-------------------------------------------------------------------------
template <typename T>
bool is_valid (const T &t)
{ return validator<T>::is_valid (t); }
bool is_valid (const T &t) noexcept
{
return validator<T>::is_valid (t);
}
//-------------------------------------------------------------------------
template <
template<size_t, typename...> class T,
size_t S,
typename ...Args
>
struct validator<T<S,Args...>> {
static bool is_valid (const T<S,Args...>&);
static bool is_valid (const T<S,Args...>&) noexcept;
};
//-------------------------------------------------------------------------
template <
template<size_t,typename...> class T,
size_t S,
typename ...Args
>
bool is_valid (const T<S,Args...> &v)
{ return validator<T<S,Args...>>::is_valid (v); }
bool is_valid (const T<S,Args...> &v) noexcept
{
return validator<T<S,Args...>>::is_valid (v);
}
//-------------------------------------------------------------------------
// forwarding validator from a pointer type to a reference type.
//
// null pointers are assumed to be invalid
template <typename T>
struct validator<T*> {
static bool is_valid (const T *val) noexcept
{
return val && ::util::debug::is_valid (*val);
}
};
///////////////////////////////////////////////////////////////////////////
// asserts that an instance of type `T' is in a valid state.
//
// behaviour will be controlled by NDEBUG and other assertion machinery and
// so may be optimised out entirely in optimised builds.
template <typename T>
void sanity (const T &t)
{
@ -465,6 +501,7 @@ namespace util::debug {
}
//-------------------------------------------------------------------------
template <
template<typename...> class T,
typename ...Args
@ -477,14 +514,16 @@ namespace util::debug {
}
#include "./debug.ipp"
#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
// after we define the CHECK_ macros so the preprocessor can resolve them.
#include "./maths.hpp"
#include "maths.hpp"
#endif // __DEBUG_HPP

View File

@ -34,7 +34,7 @@ namespace util::debug::detail {
template <typename ...Args, size_t N>
void panic [[noreturn]] (const char (&fmt)[N], const Args& ...args)
{
std::cerr << format::printf (fmt, args...) << ::debug::backtrace () << std::endl;
std::cerr << ::util::format::printf (fmt, args...) << ::debug::backtrace () << std::endl;
breakpoint ();
abort ();
}

View File

@ -15,16 +15,16 @@
* 2011-2016, Danny Robson <danny@nerdcruft.net>
*/
#include "./debug.hpp"
#include "debug.hpp"
#include "./log.hpp"
#include "log.hpp"
#include "platform.hpp"
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <signal.h>
#include "./platform.hpp"
#if defined(PLATFORM_FREEBSD)
#define PTRACE_ATTACH PT_ATTACH

View File

@ -14,11 +14,12 @@
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
*/
#include "./debug.hpp"
#include "debug.hpp"
#include "./except.hpp"
#include "./log.hpp"
#include "./except.hpp"
#include "except.hpp"
#include "log.hpp"
#include "except.hpp"
#include "win32/error.hpp"
#include <windows.h>
#include <iostream>
@ -49,7 +50,7 @@ prepare_debugger (void)
{
if (nullptr == LoadLibrary("exchndl.dll")) {
auto code = GetLastError ();
LOG_WARNING("Emergency debugger not loaded: %s", util::win32_error::code_string (code));
LOG_WARNING("Emergency debugger not loaded: %s", util::win32::error::code_string (code));
}
}

View File

@ -11,18 +11,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_TIME_IPP
#define __UTIL_TIME_IPP
#include "base.hpp"
template <typename T>
void
util::sleep (std::chrono::duration<T,std::nano> dt)
{
auto nano = std::chrono::duration_cast<std::chrono::nanoseconds> (dt);
sleep (nano.count ());
}
#endif

251
encode/base.hpp Normal file
View File

@ -0,0 +1,251 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#ifndef CRUFT_UTIL_BASE64_HPP
#define CRUFT_UTIL_BASE64_HPP
#include "../view.hpp"
#include "../debug.hpp"
#include <cstdint>
#include <array>
namespace util::encode {
///////////////////////////////////////////////////////////////////////////
template <int Size>
struct alphabet {
static const char enc[Size];
static const uint8_t dec[256];
};
///////////////////////////////////////////////////////////////////////////
template <>
const char alphabet<64>::enc[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
};
//-------------------------------------------------------------------------
template <>
const uint8_t alphabet<64>::dec[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3E, 0, 0, 0, 0x3F,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0, 0, 0, 0, 0, 0,
0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0, 0, 0, 0, 0,
0, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
///////////////////////////////////////////////////////////////////////////
template <>
const char alphabet<32>::enc[32] {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'2', '3', '4', '5', '6', '7',
};
//-------------------------------------------------------------------------
template <>
const uint8_t alphabet<32>::dec[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
///////////////////////////////////////////////////////////////////////////
template <>
const char alphabet<16>::enc[16] {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
};
template <>
const uint8_t alphabet<16>::dec[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0, 0, 0, 0, 0, 0,
0, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
//-------------------------------------------------------------------------
template <int Size> constexpr auto enc_v = alphabet<Size>::enc;
template <int Size> constexpr auto dec_v = alphabet<Size>::dec;
///////////////////////////////////////////////////////////////////////////
/// rfc4648 base16, base32, and base64 encoding
template <int Size>
struct base {
static constexpr auto symbol_bits = log2 (Size);
static constexpr auto group_bits = std::lcm (symbol_bits, 8);
static constexpr auto group_symbols = group_bits / symbol_bits;
static constexpr auto group_bytes = group_bits / 8;
static constexpr uint_fast32_t mask = (1<<symbol_bits)-1;
template <typename InputT, typename OutputT>
static OutputT
encode (OutputT dst, const util::view<InputT> src)
{
// convert whole groups of symbols while we have enough bytes remaining
auto cursor = std::cbegin (src);
for (size_t i = 0, last = std::size (src) / group_bytes; i != last; ++i) {
auto tally = std::accumulate (
cursor, cursor + group_bytes,
uint_fast32_t {0},
[] (auto a, auto b) { return a << 8 | b; }
);
cursor += group_bytes;
for (int j = group_symbols - 1; j >= 0; --j)
*dst++ = enc_v<Size>[tally >> (j * symbol_bits) & mask];
}
// we don't need to pad the output so we can early exit
if (cursor == std::cend (src))
return dst;
// accumulate the remaining bits and pad to a multiple of the
// output group length
auto tally = std::accumulate (
cursor,
std::cend (src),
uint_fast32_t {0},
[] (auto a, auto b) { return a << 8 | b; }
);
auto input_remain = std::cend (src) - cursor;
tally <<= symbol_bits - input_remain * 8 % symbol_bits;
// write each of the remaining symbols
auto output_remain = (input_remain * 8 + symbol_bits - 1) / symbol_bits;
for (auto i = output_remain - 1; i >= 0; --i)
*dst++ = enc_v<Size>[tally >> (i * symbol_bits) & mask];
// pad the output to the symbol group size with '=' characters
auto fill = (group_bytes - input_remain) * 8 / symbol_bits;
return std::fill_n (dst, fill, '=');
}
//---------------------------------------------------------------------
template <typename InputT, typename OutputT>
static OutputT
decode (OutputT dst, util::view<InputT> src)
{
if (src.empty ())
return dst;
if (src.size () % group_symbols)
throw std::invalid_argument ("base-encoded strings must be a proper multiple of symbols");
union {
uint_fast32_t num;
uint8_t bytes[group_bytes];
};
const bool padded = src.end ()[-1] == '=';
auto cursor = std::cbegin (src);
for (size_t i = 0, last = std::size (src) / group_symbols - padded?1:0;
i != last;
++i)
{
num = std::accumulate (
cursor, cursor + group_symbols,
uint_fast32_t {0},
[] (auto a, auto b) {
return a << symbol_bits | dec_v<Size>[static_cast<unsigned>(b)];
}
);
cursor += group_symbols;
dst = std::copy (std::crbegin (bytes), std::crend (bytes), dst);
}
if (cursor != std::end (src)) {
auto last = std::find (cursor, std::cend (src), '=');
num = std::accumulate (
cursor, last,
uint_fast32_t{0},
[] (auto a, auto b) {
return a << symbol_bits | dec_v<Size>[static_cast<unsigned> (b)];
}
);
auto symbols = last - cursor;
auto bits = symbols * symbol_bits;
auto shift = bits%8;
num >>= shift;
for (auto i = bits / 8; i; )
*dst++ = bytes[--i];
}
return dst;
}
};
};
#endif

View File

@ -1,202 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2010 Danny Robson <danny@nerdcruft.net>
*/
#include "./except.hpp"
#include "./debug.hpp"
#include "./platform.hpp"
#include <cstring>
#include <cerrno>
using util::errno_error;
///////////////////////////////////////////////////////////////////////////////
/// Construct an errno_error from a given error value. The error value MUST signal an error at
/// construction time.
errno_error::errno_error (int _code):
runtime_error (strerror (_code)),
m_code (_code)
{
CHECK_NEQ (_code, 0);
}
///----------------------------------------------------------------------------
/// Construct an errno_error from the current value of errno. errno MUST signal an error at
/// construction time.
errno_error::errno_error ():
errno_error (last_code ())
{
CHECK_NEQ (m_code, 0);
}
///////////////////////////////////////////////////////////////////////////////
int
errno_error::last_code (void)
{
return errno;
}
//-----------------------------------------------------------------------------
int
errno_error::code (void) const
{
return m_code;
}
///////////////////////////////////////////////////////////////////////////////
/// Throw an errno_error exception if errno currently signals an error.
void
errno_error::try_code (void)
{
try_code (last_code ());
}
///----------------------------------------------------------------------------
/// Throw an errno_error exception if 'code' represents an error.
void
errno_error::try_code (int code)
{
if (__builtin_expect (code != 0, false))
throw errno_error(code);
}
///----------------------------------------------------------------------------
void
errno_error::throw_code (void)
{
throw_code (last_code ());
}
///----------------------------------------------------------------------------
void
errno_error::throw_code (int code)
{
CHECK_NEQ (code, 0);
throw errno_error (code);
}
///////////////////////////////////////////////////////////////////////////////
#if defined(PLATFORM_WIN32)
using util::win32_error;
//-----------------------------------------------------------------------------
win32_error::win32_error (DWORD _code):
runtime_error (code_string (_code)),
m_code (_code)
{
CHECK_NEQ (m_code, (DWORD)ERROR_SUCCESS);
}
//-----------------------------------------------------------------------------
win32_error::win32_error (void):
win32_error (last_code ())
{ ; }
///////////////////////////////////////////////////////////////////////////////
DWORD
win32_error::code (void) const
{
return m_code;
}
//-----------------------------------------------------------------------------
DWORD
win32_error::last_code (void)
{
return GetLastError ();
}
///////////////////////////////////////////////////////////////////////////////
void
win32_error::try_code (void)
{
try_code (last_code ());
}
//-----------------------------------------------------------------------------
void
win32_error::try_code (DWORD id)
{
if (__builtin_expect (id != ERROR_SUCCESS, false))
throw_code (id);
}
//-----------------------------------------------------------------------------
void
win32_error::throw_code (void)
{
throw_code (last_code ());
}
//-----------------------------------------------------------------------------
void
win32_error::throw_code (DWORD code)
{
CHECK_NEQ (code, (DWORD)ERROR_SUCCESS);
throw win32_error (code);
}
//-----------------------------------------------------------------------------
std::string
win32_error::code_string (void)
{
return code_string (last_code ());
}
//-----------------------------------------------------------------------------
std::string
win32_error::code_string (DWORD code)
{
char message[256];
auto res = FormatMessage (
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
code,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
message,
std::size (message),
NULL
);
if (res == 0) {
win32_error::throw_code ();
}
return std::string (message, message + res);
}
#endif

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 2010 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __EXCEPT_HPP
#define __EXCEPT_HPP
#include "platform.hpp"
#include <stdexcept>
namespace util {
class input_error : public std::runtime_error {
public:
explicit input_error (const std::string &_what):
runtime_error (_what)
{ ; }
};
class output_error : public std::runtime_error {
public:
explicit output_error (const std::string &_what):
runtime_error (_what)
{ ; }
};
class unavailable_error : public std::runtime_error {
public:
explicit unavailable_error (const std::string &_what):
runtime_error (_what)
{ ; }
};
/// An exception class used for reporting errors signalled by errno.
class errno_error : public std::runtime_error {
public:
explicit errno_error (int code);
errno_error ();
int code (void) const;
static int last_code (void);
static void try_code (void);
static void try_code (int code);
static void throw_code [[gnu::noreturn]] (void);
static void throw_code [[gnu::noreturn]] (int code);
private:
int m_code;
};
}
#if defined(PLATFORM_WIN32)
#include <windows.h>
namespace util {
class win32_error : public std::runtime_error {
public:
explicit win32_error (DWORD _code);
win32_error ();
DWORD code (void) const;
static DWORD last_code (void);
static void try_code (void);
static void try_code (DWORD);
static void throw_code [[gnu::noreturn]] (void);
static void throw_code [[gnu::noreturn]] (DWORD);
static std::string code_string (void);
static std::string code_string (DWORD);
private:
DWORD m_code;
};
}
#endif
#endif

View File

@ -14,10 +14,10 @@
* Copyright 2010-2016 Danny Robson <danny@nerdcruft.net>
*/
#include "./exe.hpp"
#include "exe.hpp"
#include "./except.hpp"
#include "./cast.hpp"
#include "cast.hpp"
#include "posix/except.hpp"
#include <vector>
#include <experimental/filesystem>
@ -39,7 +39,7 @@ util::image_path (void)
retry:
const auto written = readlink (PROC_SELF, resolved.data (), resolved.size ());
if (written < 0)
errno_error::throw_code ();
posix::error::throw_code ();
if (sign_cast<size_t> (written) == resolved.size ()) {
resolved.resize (resolved.size () * 2);

View File

@ -14,9 +14,10 @@
* Copyright 2010-2016 Danny Robson <danny@nerdcruft.net>
*/
#include "./exe.hpp"
#include "exe.hpp"
#include "except.hpp"
#incldue "win32/except.hpp"
#include <experimental/filesystem>
#include <vector>
@ -32,7 +33,7 @@ util::image_path (void)
retry:
const auto written = GetModuleFileName (nullptr, resolved.data (), resolved.size ());
if (written == 0)
win32_error::throw_code ();
win32::error::throw_code ();
if (written == resolved.size ()) {
resolved.resize (resolved.size () * 2);

View File

@ -14,10 +14,10 @@
* Copyright 2010-2016 Danny Robson <danny@nerdcruft.net>
*/
#include "./extent.hpp"
#include "extent.hpp"
#include "./debug.hpp"
#include "./maths.hpp"
#include "debug.hpp"
#include "maths.hpp"
#include <algorithm>
#include <numeric>
@ -187,9 +187,9 @@ namespace util::debug {
//-----------------------------------------------------------------------------
#define INSTANTIATE_S_T(S,T) \
template struct util::extent<S,T>; \
template bool util::debug::is_valid (const extent<S,T>&); \
template struct util::debug::validator<extent<S,T>>;
template struct ::util::extent<S,T>; \
template bool ::util::debug::is_valid (const ::util::extent<S,T>&); \
template struct ::util::debug::validator<::util::extent<S,T>>;
#define INSTANTIATE(T) \
INSTANTIATE_S_T(1,T) \

View File

@ -17,22 +17,24 @@
#ifndef __UTIL_EXTENT_HPP
#define __UTIL_EXTENT_HPP
#include "coord/fwd.hpp"
#include "coord/base.hpp"
#include "vector.hpp"
#include "point.hpp"
#include <cstddef>
namespace util {
/**
* A pure two-dimensional size, without positioning
* A pure n-dimensional size, without positioning
*/
template <size_t S, typename T>
struct extent : public coord::base<S,T,extent,coord::whd>
struct extent : public ::util::coord::base<S,T,::util::extent<S,T>>
{
using coord::base<S,T,util::extent,coord::whd>::base;
using ::util::coord::base<S,T,::util::extent<S,T>>::base;
extent () = default;
explicit extent (vector<S,T>);
explicit extent (::util::vector<S,T>);
constexpr T area (void) const;
constexpr T diameter (void) const;
@ -41,7 +43,6 @@ namespace util {
constexpr
U aspect (void) const;
/// tests whether a point would lie within:
/// region { origin, *this }, inclusive of borders.
///
@ -62,24 +63,27 @@ namespace util {
return all (p >= T{0} && p < *this);
}
extent expanded (vector<S,T>) const;
extent expanded (T) const;
extent contracted (vector<S,T>) const;
extent contracted (T) const;
::util::extent<S,T> expanded (::util::vector<S,T>) const;
::util::extent<S,T> expanded (T) const;
::util::extent<S,T> contracted (::util::vector<S,T>) const;
::util::extent<S,T> contracted (T) const;
bool empty (void) const;
static constexpr extent max (void);
static constexpr extent min (void);
static constexpr ::util::extent<S,T> max (void);
static constexpr ::util::extent<S,T> min (void);
};
template <size_t S, typename T>
struct extent_range {
public:
struct iterator : public std::iterator<std::forward_iterator_tag, point<S,T>, size_t> {
struct iterator : public std::iterator<
std::forward_iterator_tag,
::util::point<S,T>,
size_t
> {
public:
iterator (extent<S,T>, util::point<S,T>);
iterator (::util::extent<S,T>, ::util::point<S,T>);
point<S,T> operator* () const;
iterator& operator++ (void);

View File

@ -17,9 +17,9 @@
#ifndef __UTIL_FIXED_HPP
#define __UTIL_FIXED_HPP
#include "./types/bits.hpp"
#include "./maths.hpp"
#include "./endian.hpp"
#include "types/bits.hpp"
#include "maths.hpp"
#include "endian.hpp"
#include <ostream>

View File

@ -1 +1 @@
#include "./filesystem.hpp"
#include "filesystem.hpp"

View File

@ -14,7 +14,7 @@
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
*/
#include "./filesystem.hpp"
#include "filesystem.hpp"
#include "../../except.hpp"

View File

@ -17,7 +17,6 @@
#ifndef CRUFT_UTIL_FORMAT_HPP
#define CRUFT_UTIL_FORMAT_HPP
#include "maths.hpp"
#include "view.hpp"
#include <algorithm>
@ -413,7 +412,7 @@ namespace util::format {
static std::ostream&
write (std::ostream &os, specifier s, const std::nullptr_t &val)
{
if (s.type != type_t::POINTER)
if (s.type != type_t::POINTER || s.type == type_t::USER)
throw std::runtime_error ("expected pointer specifier");
return value<const void*>::write (os, s, val);
}
@ -424,8 +423,9 @@ namespace util::format {
struct value<const char[N]> {
static std::ostream&
write (std::ostream &os, specifier spec, const char (&val)[N]) {
if (spec.type == type_t::STRING)
if (spec.type == type_t::STRING || spec.type == type_t::USER)
return value<util::view<const char*>>::write (os, spec, util::view<const char*> (val));
throw std::runtime_error ("invalid data type");
}
};
@ -445,7 +445,7 @@ namespace util::format {
write (std::ostream &os, specifier spec, char *val) {
if (!val)
return os << "(nil)";
if (spec.type == type_t::STRING)
if (spec.type == type_t::STRING || spec.type == type_t::USER)
return value<util::view<const char*>>::write (os, spec, util::view<const char*> { val, val + strlen (val) });
if (spec.type == type_t::POINTER)
return value<const void*>::write (os, spec, val);
@ -460,7 +460,7 @@ namespace util::format {
write (std::ostream &os, specifier spec, const char *val) {
if (!val)
return os << "(nil)";
if (spec.type == type_t::STRING)
if (spec.type == type_t::STRING || spec.type == type_t::USER)
return value<util::view<const char*>>::write (os, spec, util::view<const char*> { val, val + strlen (val) });
if (spec.type == type_t::POINTER)
return value<const void*>::write (os, spec, val);

View File

@ -15,9 +15,9 @@
*/
#include "./aabb.hpp"
#include "aabb.hpp"
#include "./iostream.hpp"
#include "iostream.hpp"
#include "../coord/iostream.hpp"
#include "../debug.hpp"
@ -61,52 +61,6 @@ aabb<S,T>::closest (const point<S,T> q) const
}
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
aabb<S,T>
aabb<S,T>::expand (const vector<S,T> mag) const noexcept
{
CHECK (all (mag >= T{0}));
return { p0 - mag, p1 + mag };
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
aabb<S,T>
aabb<S,T>::expand (const T mag) const noexcept
{
CHECK_GE (mag, T{0});
return { p0 - mag, p1 + mag };
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
aabb<S,T>
aabb<S,T>::contract (const util::vector<S,T> mag) const noexcept
{
CHECK (all (mag >= T{0}));
CHECK (all (2 * mag <= p1 - p0));
return { p0 + mag, p1 - mag };
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
aabb<S,T>
aabb<S,T>::contract (const T mag) const noexcept
{
CHECK_GE (mag, T{0});
CHECK (all (2 * mag <= p1 - p0));
return { p0 + mag, p1 - mag };
}
//-----------------------------------------------------------------------------
template <size_t S, typename T>
void

View File

@ -44,19 +44,13 @@ namespace util::geom {
point<S,T> closest (point<S,T>) const;
aabb<S,T> expand (util::vector<S,T>) const noexcept;
aabb<S,T> expand (T) const noexcept;
aabb<S,T> contract (util::vector<S,T>) const noexcept;
aabb<S,T> contract (T) const noexcept;
void cover (point<S,T>);
aabb<S,T> operator+ (vector<S,T>) const;
aabb<S,T> operator- (vector<S,T>) const;
point<S,T> p0;
point<S,T> p1;
::util::point<S,T> p0;
::util::point<S,T> p1;
};

View File

@ -14,9 +14,9 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "./iostream.hpp"
#include "iostream.hpp"
#include "./sphere.hpp"
#include "sphere.hpp"
#include "../coord/iostream.hpp"

View File

@ -17,7 +17,7 @@
#ifndef __UTIL_GEOM_IOSTREAM_HPP
#define __UTIL_GEOM_IOSTREAM_HPP
#include "./fwd.hpp"
#include "fwd.hpp"
#include <ostream>

View File

@ -24,8 +24,7 @@ using util::geom::plane;
///////////////////////////////////////////////////////////////////////////////
template <size_t S, typename T>
plane<S,T>::plane (point<S,T> _p,
vector<S,T> _n):
plane<S,T>::plane (point<S,T> _p, vector<S,T> _n):
p (_p),
n (_n)
{

View File

@ -23,11 +23,10 @@
namespace util::geom {
template <size_t S, typename T>
struct plane {
plane (util::point<S,T> p,
util::vector<S,T> n);
plane (util::point<S,T>, util::vector<S,T>);
util::point<S,T> p;
util::vector<S,T> n;
::util::point<S,T> p;
::util::vector<S,T> n;
};

View File

@ -14,10 +14,10 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "./ray.hpp"
#include "ray.hpp"
#include "./iostream.hpp"
#include "./ops.hpp"
#include "iostream.hpp"
#include "ops.hpp"
#include "../coord/iostream.hpp"
#include "../debug.hpp"

View File

@ -14,9 +14,9 @@
* Copyright 2010-2014 Danny Robson <danny@nerdcruft.net>
*/
#include "./adler.hpp"
#include "adler.hpp"
#include "./fletcher.hpp"
#include "fletcher.hpp"
#include "../debug.hpp"
static constexpr unsigned MODULUS = 65521;

View File

@ -17,7 +17,7 @@
#ifndef __UTIL_HASH_ADLER_HPP
#define __UTIL_HASH_ADLER_HPP
#include "./fletcher.hpp"
#include "fletcher.hpp"
#include <cstdint>

View File

@ -48,9 +48,8 @@ bsdsum::update (const void *restrict data, size_t size) noexcept
///////////////////////////////////////////////////////////////////////////////
void
bsdsum::update (
const uint8_t *const restrict first,
const uint8_t *const restrict last) noexcept
bsdsum::update (const uint8_t *const restrict first,
const uint8_t *const restrict last) noexcept
{
CHECK (first);
CHECK (last);

View File

@ -14,7 +14,7 @@
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
*/
#include "./crc.hpp"
#include "crc.hpp"
#include "../bitwise.hpp"
#include "../debug.hpp"

View File

@ -15,7 +15,7 @@
*/
#include "./fletcher.hpp"
#include "fletcher.hpp"
#include "../debug.hpp"

View File

@ -21,9 +21,9 @@
// directly, and are unlikely to change given their inherent
// lightweight nature.
#include "./fasthash.hpp"
#include "./fnv1a.hpp"
#include "./murmur.hpp"
#include "fasthash.hpp"
#include "fnv1a.hpp"
#include "murmur.hpp"
// Forward declerations of class based hashes

View File

@ -1,4 +1,4 @@
#include "./keccak.hpp"
#include "keccak.hpp"
#include "../endian.hpp"
#include "../maths.hpp"

View File

@ -17,8 +17,8 @@
#ifndef __UTIL_HASH_MURMUR_HPP
#define __UTIL_HASH_MURMUR_HPP
#include "./murmur/murmur1.hpp"
#include "./murmur/murmur2.hpp"
#include "./murmur/murmur3.hpp"
#include "murmur/murmur1.hpp"
#include "murmur/murmur2.hpp"
#include "murmur/murmur3.hpp"
#endif

View File

@ -31,7 +31,7 @@ namespace util::hash::murmur2 {
uint64_t hash_64 (const void *restrict data, size_t len, uint64_t seed);
}
#include "./murmur2.ipp"
#include "murmur2.ipp"
#endif

View File

@ -15,7 +15,7 @@
* 2014, Danny Robson <danny@nerdcruft.net>
*/
#include "./ripemd.hpp"
#include "ripemd.hpp"
#include "../debug.hpp"
#include "../bitwise.hpp"

View File

@ -14,7 +14,7 @@
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
*/
#include "./sha1.hpp"
#include "sha1.hpp"
#include "../bitwise.hpp"
#include "../debug.hpp"

View File

@ -14,4 +14,4 @@
* Copyright 2016, Danny Robson <danny@nerdcruft.net>
*/
#include "./simple.hpp"
#include "simple.hpp"

View File

@ -14,11 +14,11 @@
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
*/
#include "./xxhash.hpp"
#include "xxhash.hpp"
#include "./debug.hpp"
#include "./bitwise.hpp"
#include "./endian.hpp"
#include "../bitwise.hpp"
#include "../debug.hpp"
#include "../endian.hpp"
#include <cstring>

View File

@ -17,8 +17,8 @@
#ifndef __UTIL_INTROSPECTION_HPP
#define __UTIL_INTROSPECTION_HPP
#include "./preprocessor.hpp"
#include "./variadic.hpp"
#include "preprocessor.hpp"
#include "variadic.hpp"
#include <array>
#include <cstddef>

31
io.cpp
View File

@ -17,9 +17,9 @@
#include "io.hpp"
#include "debug.hpp"
#include "except.hpp"
#include "cast.hpp"
#include "format.hpp"
#include "posix/except.hpp"
#include <cstdio>
#include <fcntl.h>
@ -45,12 +45,9 @@ util::slurp (const std::experimental::filesystem::path &path)
posix::fd out (path, O_RDONLY | O_BINARY);
// Calculate the total file size
off_t size = lseek (out, 0, SEEK_END);
if (size == (off_t)-1)
throw errno_error();
off_t size = posix::error::try_value (lseek (out, 0, SEEK_END));
if (lseek (out, 0, SEEK_SET) == (off_t)-1)
throw errno_error ();
posix::error::try_value (lseek (out, 0, SEEK_SET));
// Allocate a buffer, and keep reading until it's full.
std::vector<T> buffer (size);
@ -60,9 +57,10 @@ util::slurp (const std::experimental::filesystem::path &path)
T *cursor = buffer.data ();
while (remaining) {
ssize_t consumed = ::read (out, cursor, remaining);
if (consumed == -1)
throw errno_error();
ssize_t consumed = posix::error::try_value(
::read (out, cursor, remaining)
);
CHECK_GT ( consumed, 0);
CHECK_LE ((size_t)consumed, remaining);
@ -90,13 +88,10 @@ util::slurp (FILE *stream)
);
// find how much data is in this file
const int desc = fileno (stream);
if (desc < 0)
errno_error::throw_code ();
const int desc = util::posix::error::try_value (fileno (stream));
struct stat meta;
if (fstat (desc, &meta) < 0)
errno_error::throw_code ();
posix::error::try_value (fstat (desc, &meta));
std::vector<T> buf;
@ -145,9 +140,7 @@ util::write (const posix::fd &out,
size_t remaining = bytes;
while (remaining) {
ssize_t consumed = ::write (out, cursor, remaining);
if (consumed < 0)
errno_error::throw_code ();
ssize_t consumed = posix::error::try_value (::write (out, cursor, remaining));
remaining -= sign_cast<size_t> (consumed);
cursor += sign_cast<size_t> (consumed);
@ -199,7 +192,7 @@ scoped_cwd::scoped_cwd ()
m_original.resize (16);
while (getcwd (&m_original[0], m_original.size ()) == nullptr && errno == ERANGE)
m_original.resize (m_original.size () * 2);
errno_error::try_code ();
posix::error::try_code ();
}
@ -207,7 +200,7 @@ scoped_cwd::scoped_cwd ()
scoped_cwd::~scoped_cwd ()
{
if (!chdir (m_original.c_str ()))
errno_error::throw_code ();
posix::error::throw_code ();
}

50
io.hpp
View File

@ -43,16 +43,48 @@ namespace util {
std::vector<T> slurp (FILE *);
//-------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////
void write (const posix::fd&, const void *restrict data, size_t bytes);
template <typename T>
void write (const posix::fd&, const T &data);
template <typename T>
void write (const posix::fd&, const T *restrict first, const T *restrict last);
//-------------------------------------------------------------------------
inline void
write (const posix::fd &dst, util::view<const uint8_t*> data)
{
write (dst, std::data (data), std::size (data));
}
//-------------------------------------------------------------------------
template <typename T>
void write (const posix::fd &_fd, const T &data)
{
return write (_fd, make_view (data));
}
///------------------------------------------------------------------------
/// writes all data from the provided view into the file-like-object
///
/// writing will continually iterate until the entire buffer has been
/// dispatched so as to avoid issues with partial writes. will block until
/// such time as the entire buffer has written.
///
/// an exception may be thrown in the event forward progress is impossible.
/// in this event the progress may not be reported to the caller. in the
/// future an exception member variable may expose the information.
template <typename DstT, typename IteratorA, typename IteratorB>
util::view<IteratorA,IteratorB>
write (DstT &dst, const util::view<IteratorA, IteratorB> src)
{
auto remain = src;
while (!remain.empty ())
remain = src - dst.write (remain);
return src;
}
///////////////////////////////////////////////////////////////////////////
class indenter : public std::streambuf {
protected:
std::streambuf* m_dest;
@ -120,11 +152,11 @@ namespace util {
}
#ifdef PLATFORM_WIN32
#include "./io_win32.hpp"
#include "io_win32.hpp"
#else
#include "./io_posix.hpp"
#include "io_posix.hpp"
#endif
#include "./io.ipp"
#include "io.ipp"
#endif

9
io.ipp
View File

@ -23,15 +23,6 @@
#endif
namespace util {
//-------------------------------------------------------------------------
template <typename T>
void
write (const posix::fd &_fd, const T &data)
{
write (_fd, &data, sizeof (T));
}
//-------------------------------------------------------------------------
template <typename T>
void

View File

@ -16,10 +16,10 @@
#include "io.hpp"
#include "cast.hpp"
#include "debug.hpp"
#include "except.hpp"
#include "posix/fd.hpp"
#include "./cast.hpp"
#include "posix/except.hpp"
#include <sys/stat.h>
@ -38,13 +38,12 @@ mapped_file::mapped_file (const std::experimental::filesystem::path &path,
mapped_file::mapped_file (const ::util::posix::fd &src, int mflags)
{
struct stat meta;
if (fstat (src, &meta) < 0)
throw errno_error ();
::util::posix::error::try_value (fstat (src, &meta));
m_size = sign_cast<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 ();
::util::posix::error::throw_code ();
}

View File

@ -20,7 +20,7 @@
#define __UTIL_IO_POSIX_IPP
#include "./pointer.hpp"
#include "pointer.hpp"
///////////////////////////////////////////////////////////////////////////////

View File

@ -14,10 +14,11 @@
* Copyright 2014 Danny Robson <danny@nerdcruft.net>
*/
#include "./io_win32.hpp"
#include "io_win32.hpp"
#include "./debug.hpp"
#include "./except.hpp"
#include "debug.hpp"
#include "except.hpp"
#include "win32/error.hpp"
#include <windows.h>
@ -94,11 +95,11 @@ mapped_file::mapped_file (::util::win32::handle &&src,
// hell. Try not to collapse, but instead bail with a null mapping and
// pray the user doesn't do something stupid with the result.
if (!m_mapping) {
auto err = win32_error::last_code ();
auto err = win32::error::last_code ();
if (err == ERROR_FILE_INVALID && m_size == 0)
return;
win32_error::throw_code (err);
win32::error::throw_code (err);
}
auto view = MapViewOfFile (
@ -109,7 +110,7 @@ mapped_file::mapped_file (::util::win32::handle &&src,
);
if (!view)
win32_error::throw_code ();
win32::error::throw_code ();
m_data.reset (
static_cast<unsigned char*> (view)

View File

@ -17,9 +17,9 @@
#ifndef __UTIL_IO_WIN32_HPP
#define __UTIL_IO_WIN32_HPP
#include "./io.hpp"
#include "./win32/handle.hpp"
#include "./view.hpp"
#include "io.hpp"
#include "win32/handle.hpp"
#include "view.hpp"
#include <cstdint>
#include <experimental/filesystem>

View File

@ -438,6 +438,84 @@ namespace util {
discard_iterator operator++ (int) { return *this; }
discard_iterator& operator* ( ) { return *this; }
};
///////////////////////////////////////////////////////////////////////////
/// an iterator that can be infinitely incremented but never assigned.
///
/// useful for iterator ranges where the begin iterator is an output
/// iterator and hence never reaches an end point (and where we don't want
/// to engineer the client code to account for this).
template <
typename ValueT,
typename CategoryT,
typename DistanceT,
typename PointerT,
typename ReferenceT
>
struct unequal_iterator {
using value_type = ValueT;
using iterator_category = CategoryT;
using difference_type = DistanceT;
using pointer = PointerT;
using reference = ReferenceT;
unequal_iterator& operator++ ( ) { return *this; }
unequal_iterator operator++ (int) { return *this; }
};
//-------------------------------------------------------------------------
template <typename ContainerT>
auto
make_unequal_iterator (const ContainerT&)
{
using t = typename std::iterator_traits<typename ContainerT::iterator>;
return unequal_iterator<
typename t::value_type,
typename t::iterator_category,
typename t::difference_type,
typename t::pointer,
typename t::reference
> {};
};
//-------------------------------------------------------------------------
template <
typename OtherT,
typename ValueT,
typename CategoryT,
typename DistanceT,
typename PointerT,
typename ReferenceT>
constexpr bool
operator== (
const unequal_iterator<ValueT,CategoryT,DistanceT,PointerT,ReferenceT>&,
const OtherT&
) {
return false;
}
//-------------------------------------------------------------------------
template <
typename OtherT,
typename ValueT,
typename CategoryT,
typename DistanceT,
typename PointerT,
typename ReferenceT>
constexpr bool
operator== (
const OtherT&,
const unequal_iterator<ValueT,CategoryT,DistanceT,PointerT,ReferenceT>&
) {
return false;
}
};
#endif

View File

@ -14,10 +14,10 @@
* Copyright 2015-2017 Danny Robson <danny@nerdcruft.net>
*/
#include "./schema.hpp"
#include "schema.hpp"
#include "./tree.hpp"
#include "./except.hpp"
#include "tree.hpp"
#include "except.hpp"
#include "../debug.hpp"
#include "../io.hpp"

View File

@ -17,7 +17,7 @@
#ifndef __UTIL_JSON_SCHEMA_HPP
#define __UTIL_JSON_SCHEMA_HPP
#include "./fwd.hpp"
#include "fwd.hpp"
#include <experimental/filesystem>

View File

@ -15,10 +15,10 @@
*/
#include "./tree.hpp"
#include "tree.hpp"
#include "./except.hpp"
#include "./flat.hpp"
#include "except.hpp"
#include "flat.hpp"
#include "../debug.hpp"
#include "../io.hpp"

View File

@ -17,8 +17,8 @@
#ifndef __UTIL_JSON_TREE_HPP
#define __UTIL_JSON_TREE_HPP
#include "./flat.hpp"
#include "./fwd.hpp"
#include "flat.hpp"
#include "fwd.hpp"
#include "../iterator.hpp"
#include "../view.hpp"

View File

@ -16,7 +16,7 @@
#include "library_win32.hpp"
#include "except.hpp"
#include "win32/except.hpp"
using util::detail::win32::library;
@ -26,7 +26,7 @@ library::library (const std::experimental::filesystem::path &path):
m_handle (LoadLibraryA (path.c_str ()))
{
if (!m_handle)
win32_error::throw_code ();
win32::error::throw_code ();
}

View File

@ -31,27 +31,6 @@ template uint32_t util::log2up (uint32_t);
template uint64_t util::log2up (uint64_t);
///////////////////////////////////////////////////////////////////////////////
template <typename T>
T
util::log2 (T v)
{
static_assert (std::is_integral<T>::value,
"log2 is only implemented for integers");
T l = 0;
while (v >>= 1)
++l;
return l;
}
template uint8_t util::log2 (uint8_t);
template uint16_t util::log2 (uint16_t);
template uint32_t util::log2 (uint32_t);
template uint64_t util::log2 (uint64_t);
///////////////////////////////////////////////////////////////////////////////
template const float util::PI<float>;
template const double util::PI<double>;

View File

@ -21,8 +21,8 @@
// it triggers a circular dependency; debug -> format -> maths -> debug
// instead, just use cassert
#include "./types/traits.hpp"
#include "./float.hpp"
#include "types/traits.hpp"
#include "float.hpp"
#include <algorithm>
#include <cassert>
@ -81,8 +81,8 @@ namespace util {
template <typename A, typename B>
inline
typename std::enable_if_t<
std::is_integral<A>::value &&
std::is_integral<B>::value &&
std::is_integral_v<A> &&
std::is_integral_v<B> &&
std::is_signed<A>::value == std::is_signed<B>::value,
bool
>
@ -203,7 +203,7 @@ namespace util {
///////////////////////////////////////////////////////////////////////////
template <typename T>
T
std::enable_if_t<std::is_arithmetic_v<T>, T>
abs [[gnu::const]] (T t)
{
return t > 0 ? t : -t;
@ -221,11 +221,19 @@ namespace util {
///////////////////////////////////////////////////////////////////////////
template <typename T>
constexpr T
pow [[gnu::const]] (T x, unsigned y)
template <
typename BaseT,
typename ExponentT,
typename = std::enable_if_t<
std::is_unsigned_v<ExponentT>,
void
>
>
constexpr BaseT
pow [[gnu::const]] (BaseT base, ExponentT exponent)
{
return y == 0 ? T{1} : x * pow (x, y - 1);
assert (exponent >= 0);
return exponent == 0 ? BaseT{1} : base * pow (base, exponent - 1);
}
@ -242,8 +250,15 @@ namespace util {
//-----------------------------------------------------------------------------
// Logarithms
template <typename T>
T
log2 (T val);
constexpr
std::enable_if_t<std::is_integral_v<T>, T>
log2 (T val)
{
T tally = 0;
while (val >>= 1)
++tally;
return tally;
}
//-------------------------------------------------------------------------
@ -326,11 +341,29 @@ namespace util {
}
//-----------------------------------------------------------------------------
constexpr
unsigned
digits10 (uint32_t v) noexcept
//-------------------------------------------------------------------------
template <
typename NumericT,
typename = std::enable_if_t<
std::is_integral_v<NumericT>,
void
>
>
constexpr auto
digits10 (NumericT v) noexcept
{
// cascading conditionals are faster, but it's super annoying to write
// out for arbitrarily sized types so we use this base case unti
// there's actually a performance reason to use another algorithm.
int tally = 0;
do {
v /= 10;
++tally;
} while (v);
return tally;
/*
return (v >= 1000000000) ? 10 :
(v >= 100000000) ? 9 :
(v >= 10000000) ? 8 :
@ -341,6 +374,7 @@ namespace util {
(v >= 100) ? 3 :
(v >= 10) ? 2 :
1;
*/
}
@ -587,7 +621,16 @@ namespace util {
///////////////////////////////////////////////////////////////////////////
/// Variadic minimum
template <typename T>
// disable the single parameter version for non-arithmetic types so that
// min for coord types is unambiguous. allow pointers too because it
// doesn't add ambiguity and it simplifies some memory juggling.
template <
typename T,
typename = std::enable_if_t<
std::is_arithmetic_v<T> || std::is_pointer_v<T>, void
>
>
constexpr T
min (const T a)
{ return a; }
@ -609,9 +652,9 @@ namespace util {
//-------------------------------------------------------------------------
/// Variadic maximum
template <typename T>
constexpr T
constexpr std::enable_if_t<std::is_arithmetic_v<T> || std::is_pointer_v<T>, T>
max (const T a)
{ return a; }
{ return a; }
//-------------------------------------------------------------------------

View File

@ -27,7 +27,8 @@ using util::matrix;
///////////////////////////////////////////////////////////////////////////////
//template <size_t S, typename T>
//-----------------------------------------------------------------------------
//template <std::size_t S, typename T>
//matrix<S,T>&
//matrix<S,T>::invert_affine (void)
//{
@ -76,7 +77,7 @@ using util::matrix;
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
T
util::matrix<Rows,Cols,T>::determinant (void) const
{
@ -85,7 +86,7 @@ util::matrix<Rows,Cols,T>::determinant (void) const
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
util::matrix<Rows,Cols,T>
util::matrix<Rows,Cols,T>::inverse (void) const
{
@ -94,14 +95,14 @@ util::matrix<Rows,Cols,T>::inverse (void) const
///////////////////////////////////////////////////////////////////////////////
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
matrix<Cols,Rows,T>
util::transposed (const matrix<Rows,Cols,T> &m)
{
util::matrix<Cols,Rows,T> res;
for (size_t y = 0; y < Rows; ++y)
for (size_t x = 0; x < Cols; ++x)
for (std::size_t y = 0; y < Rows; ++y)
for (std::size_t x = 0; x < Cols; ++x)
res[y][x] = m[x][y];
return res;
@ -114,42 +115,14 @@ template util::matrix4f util::transposed (const matrix4f&);
///////////////////////////////////////////////////////////////////////////////
template <size_t Rows, size_t Cols, typename T>
util::vector<Rows,T>
matrix<Rows,Cols,T>::operator* (const vector<Rows,T> &rhs) const
{
vector<Rows,T> out;
for (size_t i = 0; i < Rows; ++i)
out[i] = dot (rhs, values[i]);
return out;
}
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
util::point<Rows,T>
matrix<Rows,Cols,T>::operator* (const point<Rows,T> &rhs) const
{
point<Rows,T> out;
for (size_t i = 0; i < Rows; ++i)
out[i] = dot (rhs, values[i]);
return out;
}
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
bool
matrix<Rows,Cols,T>::is_affine (void) const
{
if (Rows != Cols)
return false;
for (size_t i = 0; i < Rows - 1; ++i)
for (std::size_t i = 0; i < Rows - 1; ++i)
if (!exactly_zero (values[Rows-1][i]))
return false;
@ -158,11 +131,11 @@ matrix<Rows,Cols,T>::is_affine (void) const
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
template <typename T>
util::matrix4<T>
matrix<Rows,Cols,T>::ortho (T left, T right,
T bottom, T top,
T near, T far)
util::ortho (T left, T right,
T bottom, T top,
T near, T far)
{
CHECK_GT (far, near);
@ -174,29 +147,31 @@ matrix<Rows,Cols,T>::ortho (T left, T right,
T tb = 2 / (top - bottom);
T fn = 2 / (far - near);
return { {
return {{
{ rl, 0, 0, tx },
{ 0, tb, 0, ty },
{ 0, 0, fn, tz },
{ 0, 0, 0, 1 },
} };
}};
}
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
template <typename T>
util::matrix4<T>
matrix<Rows, Cols,T>::ortho2D (T left , T right,
T bottom, T top)
util::ortho2D (T left, T right,
T bottom, T top)
{
return ortho (left, right, bottom, top, -1, 1);
return ortho (left, right, bottom, top, T{-1}, T{1});
}
template util::matrix4f util::ortho2D (float, float, float, float);
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
template <typename T>
util::matrix4<T>
matrix<Rows,Cols,T>::perspective (T fov, T aspect, range<T> Z)
util::perspective (T fov, T aspect, range<T> Z)
{
CHECK_GE (Z.lo, 0);
CHECK_GE (Z.hi, 0);
@ -216,6 +191,8 @@ matrix<Rows,Cols,T>::perspective (T fov, T aspect, range<T> Z)
} };
}
template util::matrix4f util::perspective<float> (float, float, range<float>);
//-----------------------------------------------------------------------------
// Emulates gluLookAt
@ -225,11 +202,11 @@ matrix<Rows,Cols,T>::perspective (T fov, T aspect, range<T> Z)
// Implemented for right handed world coordinates.
//
// Assumes 'up' is normalised.
template <size_t Rows, size_t Cols, typename T>
template <typename T>
util::matrix4<T>
matrix<Rows,Cols,T>::look_at (const util::point<3,T> eye,
const util::point<3,T> centre,
const util::vector<3,T> up)
util::look_at (const util::point<3,T> eye,
const util::point<3,T> centre,
const util::vector<3,T> up)
{
CHECK (is_normalised (up));
@ -244,23 +221,16 @@ matrix<Rows,Cols,T>::look_at (const util::point<3,T> eye,
{ 0, 0, 0, 1 },
}};
return rot * util::matrix4<T>::translation (0-eye);
return rot * util::translation<T> (0-eye);
}
template util::matrix4f util::look_at (util::point3f, util::point3f, util::vector3f);
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
template <typename T>
util::matrix4<T>
matrix<Rows,Cols,T>::translation (util::vector<2,T> v)
{
return translation ({v.x, v.y, 0});
}
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
util::matrix4<T>
matrix<Rows,Cols,T>::translation (util::vector<3,T> v)
util::translation (util::vector<3,T> v)
{
return { {
{ 1.f, 0.f, 0.f, v.x },
@ -271,18 +241,24 @@ matrix<Rows,Cols,T>::translation (util::vector<3,T> v)
}
template util::matrix4f util::translation (util::vector3f);
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
template <typename T>
util::matrix4<T>
matrix<Rows,Cols,T>::scale (T mag)
util::scale (T mag)
{
return scale (vector<3,T> (mag));
}
template util::matrix4f util::scale(float);
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
template <typename T>
util::matrix4<T>
matrix<Rows,Cols,T>::scale (util::vector<3,T> v)
util::scale (util::vector<3,T> v)
{
return { {
{ v.x, 0.f, 0.f, 0.f },
@ -292,11 +268,13 @@ matrix<Rows,Cols,T>::scale (util::vector<3,T> v)
} };
}
template util::matrix4f util::scale(util::vector3f);
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
template <typename T>
util::matrix4<T>
matrix<Rows,Cols,T>::rotation (T angle, util::vector<3,T> about)
util::rotation (T angle, util::vector<3,T> about)
{
CHECK (is_normalised (about));
@ -329,6 +307,7 @@ matrix<Rows,Cols,T>::rotation (T angle, util::vector<3,T> about)
} };
}
template util::matrix4f util::rotation (float, util::vector3f);
//-----------------------------------------------------------------------------
template struct util::matrix<2,2,float>;
@ -345,7 +324,7 @@ template struct util::matrix<4,4,double>;
// Uses the algorithm from:
// "Extracting Euler Angles from a Rotation Matrix" by
// Mike Day, Insomniac Games.
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
util::vector<3,T>
util::to_euler (const matrix<Rows,Cols,T> &m)
{
@ -372,24 +351,3 @@ util::to_euler (const matrix<Rows,Cols,T> &m)
template util::vector<3,float> util::to_euler (const matrix<3,3,float>&);
template util::vector<3,float> util::to_euler (const matrix<4,4,float>&);
///////////////////////////////////////////////////////////////////////////////
template <size_t Rows, size_t Cols, typename T>
std::ostream&
util::operator<< (std::ostream &os, const matrix<Rows,Cols,T> &m)
{
os << "{ ";
for (size_t i = 0; i < Rows; ++i) {
os << "{ ";
std::copy_n (m[i], Cols, util::infix_iterator<float> (os, ", "));
os << ((i == Rows - 1) ? " }" : " }, ");
}
return os << " }";
}
//-----------------------------------------------------------------------------
template std::ostream& util::operator<< (std::ostream&, const matrix<4,4,float>&);
template std::ostream& util::operator<< (std::ostream&, const matrix<4,4,double>&);

View File

@ -19,87 +19,109 @@
#include "point.hpp"
#include "range.hpp"
#include "vector.hpp"
#include "iterator.hpp"
#include <ostream>
#include <cstdlib>
#include <ostream>
namespace util {
template <size_t Rows, size_t Cols, typename T>
template <
std::size_t Rows,
std::size_t Cols,
typename T
>
struct matrix {
static constexpr auto rows = Rows;
static constexpr auto cols = Cols;
T values[Rows][Cols];
using row_t = util::vector<Cols,T>;
///////////////////////////////////////////////////////////////////////
constexpr matrix () noexcept = default;
//---------------------------------------------------------------------
constexpr matrix (const T(&_data)[Rows][Cols]) noexcept:
values {}
{
static_assert (sizeof (*this) == sizeof (T) * Rows * Cols);
for (std::size_t r = 0; r < Rows; ++r)
for (std::size_t c = 0; c < Cols; ++c)
values[r][c] = _data[r][c];
}
//---------------------------------------------------------------------
template <std::size_t S, typename SelfT>
constexpr matrix (const util::coord::base<S,T,SelfT> (&_data)[Rows]) noexcept
{
for (std::size_t r = 0; r < Rows; ++r)
for (std::size_t c = 0; c < Cols; ++c)
values[r][c] = _data[r][c];
}
///////////////////////////////////////////////////////////////////////
// index operators return a pointer into the data array so that
// multidimensional array syntax can be used transparently on this
// type.
constexpr T*
operator[] (size_t idx) noexcept
constexpr row_t& operator[] (std::size_t idx)& { return values[idx]; }
constexpr const row_t& operator[] (std::size_t idx) const& { return values[idx]; }
//---------------------------------------------------------------------
constexpr row_t*
data (void)& noexcept
{
return this->values[idx];
return &values[0];
}
//---------------------------------------------------------------------
constexpr const T*
operator[] (size_t idx) const noexcept
constexpr const row_t*
data (void) const& noexcept
{
return this->values[idx];
}
//---------------------------------------------------------------------
constexpr T*
data (void) noexcept
{
return begin ();
}
//---------------------------------------------------------------------
constexpr const T*
data (void) const noexcept
{
return begin ();
}
//---------------------------------------------------------------------
constexpr const T*
begin (void) const noexcept
{
return &(*this)[0][0];
}
//---------------------------------------------------------------------
constexpr const T*
end (void) const noexcept
{
return &(*this)[Rows][0];
}
//---------------------------------------------------------------------
constexpr T*
begin (void) noexcept
{
return &(*this)[0][0];
}
//---------------------------------------------------------------------
constexpr T*
end (void) noexcept
{
return &(*this)[Rows][0];
return &values[0];
}
//---------------------------------------------------------------------
constexpr auto
cbegin (void) const noexcept
begin (void) const& noexcept
{
return data ();
}
//---------------------------------------------------------------------
constexpr auto
begin (void)& noexcept
{
return data ();
}
//---------------------------------------------------------------------
constexpr row_t*
end (void)& noexcept
{
return &values[Rows];
}
//---------------------------------------------------------------------
constexpr const row_t*
end (void) const& noexcept
{
return &values[Rows];
}
//---------------------------------------------------------------------
constexpr auto
cbegin (void) const& noexcept
{
return begin ();
}
//---------------------------------------------------------------------
constexpr auto
cend (void) const noexcept
cend (void) const& noexcept
{
return end ();
}
@ -118,109 +140,166 @@ namespace util {
}
///////////////////////////////////////////////////////////////////////
vector<Rows,T> operator* (const vector<Rows,T>&) const;
point<Rows,T> operator* (const point<Rows,T> &) const;
template <typename VectorT>
std::enable_if_t<is_coord_v<VectorT>, VectorT>
operator* (const VectorT &rhs) const
{
VectorT out;
for (std::size_t r = 0; r < Rows; ++r)
out[r] = dot (rhs, values[r]);
return out;
}
bool is_affine (void) const;
template <typename U>
matrix<Rows,Cols,U>
cast (void) const
cast (void) const noexcept
{
util::matrix<Rows,Cols,T> out;
matrix out;
std::copy (cbegin (), cend (), std::begin (out));
return out;
}
// Perspective matrices
static matrix<4,4,T> ortho (T left, T right, T bottom, T top, T near, T far);
static matrix<4,4,T> ortho2D (T left, T right, T bottom, T top);
static matrix<4,4,T> perspective (T fov, T aspect, range<T> Z);
static matrix<4,4,T> look_at (point<3,T> eye, point<3,T> target, vector<3,T> up);
// Affine matrices
static matrix<4,4,T> translation (util::vector<2,T>);
static matrix<4,4,T> translation (util::vector<3,T>);
static matrix<4,4,T> scale (util::vector<3,T>);
static matrix<4,4,T> scale (T);
static matrix<4,4,T> rotation (T angle, util::vector<3,T> about);
// Constant matrices
static constexpr matrix identity ();
static constexpr matrix zeroes ();
static constexpr
matrix identity (void) noexcept
{
auto m = zeroes ();
for (std::size_t i = 0; i < Rows; ++i)
m[i][i] = 1;
return m;
}
static constexpr
matrix zeroes (void) noexcept
{
matrix ret {};
std::fill (std::begin (ret), std::end (ret), row_t{0});
return ret;
}
private:
row_t values[Rows];
};
// Perspective matrices
template <typename T> matrix<4,4,T> ortho (T left, T right, T bottom, T top, T near, T far);
template <typename T> matrix<4,4,T> ortho2D (T left, T right, T bottom, T top);
template <typename T> matrix<4,4,T> perspective (T fov, T aspect, range<T> Z);
template <typename T> matrix<4,4,T> look_at (point<3,T> eye, point<3,T> target, vector<3,T> up);
// Affine matrices
template <typename T> matrix<4,4,T> translation (vector<3,T>);
template <typename T> matrix<4,4,T> scale (vector<3,T>);
template <typename T> matrix<4,4,T> scale (T);
template <typename T> matrix<4,4,T> rotation (T angle, vector<3,T> about);
///////////////////////////////////////////////////////////////////////////
// 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 Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
vector<3,T>
to_euler (const matrix<Rows, Cols, T>&);
///////////////////////////////////////////////////////////////////////////
// logical operations
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
constexpr
bool
operator== (const matrix<Rows,Cols,T>&, const matrix<Rows,Cols,T>&);
operator== (const matrix<Rows,Cols,T> &a, const matrix<Rows,Cols,T> &b)
{
return std::equal (std::cbegin (a), std::cend (a), std::cbegin (b));
}
template <size_t Rows, size_t Cols, typename T>
//-------------------------------------------------------------------------
template <std::size_t Rows, std::size_t Cols, typename T>
constexpr
bool
operator!= (const matrix<Rows,Cols,T>&, const matrix<Rows,Cols,T>&);
operator!= (const matrix<Rows,Cols,T> &a, const matrix<Rows,Cols,T> &b)
{
return !(a == b);
}
///////////////////////////////////////////////////////////////////////////
// element operations
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
constexpr
matrix<Rows,Cols,T>
operator+ (const matrix<Rows,Cols,T>&, const matrix<Rows,Cols,T>&);
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
constexpr
matrix<Rows,Cols,T>
operator- (const matrix<Rows,Cols,T>&, const matrix<Rows,Cols,T>&);
template <std::size_t Rows, std::size_t Cols, typename T>
constexpr
matrix<Rows,Cols,T>
div (const matrix<Rows,Cols,T> &a, const matrix<Rows,Cols,T> &b)
{
matrix<Rows,Cols,T> out {};
for (std::size_t r = 0; r < Rows; ++r)
for (std::size_t c = 0; c < Cols; ++c)
out[r][c] = a[r][c] / b[r][c];
return out;
}
template <std::size_t Rows, std::size_t Cols, typename T>
constexpr T
max (const matrix<Rows,Cols,T> &m)
{
T val = m[0][0];
for (std::size_t r = 0; r < Rows; ++r)
for (std::size_t c = 0; c < Cols; ++c)
val = max (val, m[r][c]);
return val;
}
///////////////////////////////////////////////////////////////////////////
// scalar operations
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator* (const matrix<R,C,T>&, T);
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator/ (const matrix<R,C,T>&, T);
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator+ (const matrix<R,C,T>&, T);
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator- (const matrix<R,C,T>&, T);
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator* (const matrix<R,C,T>&, T);
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator/ (const matrix<R,C,T>&, T);
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator+ (const matrix<R,C,T>&, T);
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator- (const matrix<R,C,T>&, T);
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator* (T, const matrix<R,C,T>&);
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator/ (T, const matrix<R,C,T>&);
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator+ (T, const matrix<R,C,T>&);
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T> operator- (T, const matrix<R,C,T>&);
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator* (T, const matrix<R,C,T>&);
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator/ (T, const matrix<R,C,T>&);
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator+ (T, const matrix<R,C,T>&);
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T> operator- (T, const matrix<R,C,T>&);
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T>& operator*= (matrix<R,C,T>&, T);
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T>& operator/= (matrix<R,C,T>&, T);
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T>& operator+= (matrix<R,C,T>&, T);
template <size_t R, size_t C, typename T> constexpr matrix<R,C,T>& operator-= (matrix<R,C,T>&, T);
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T>& operator*= (matrix<R,C,T>&, T);
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T>& operator/= (matrix<R,C,T>&, T);
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T>& operator+= (matrix<R,C,T>&, T);
template <std::size_t R, std::size_t C, typename T> constexpr matrix<R,C,T>& operator-= (matrix<R,C,T>&, T);
///////////////////////////////////////////////////////////////////////////
// matrix operations
template <
size_t R1, size_t C1,
size_t R2, size_t C2,
std::size_t R1, //int C1,
std::size_t RC, //int R2,
std::size_t C2,
typename T
>
constexpr
matrix<R1,C2,T>
operator* (const matrix<R1,C1,T> &a, const matrix<R2,C2,T> &b) noexcept
operator* (const matrix<R1,RC,T>&a, const matrix<RC,C2,T>&b)
{
static_assert (R2 == C1);
matrix<R1,C2,T> res {0};
matrix<R1,C2,T> res {};
// TODO: iterating over r,c rather than c,r will cause an ICE with
// clang#xxxx: 'X86 DAG->DAG Instruction Selection'.
@ -228,11 +307,11 @@ namespace util {
// this is likely related to gold and LTO support. for the time being
// we switch the orders because it appears to confuse the optimiser
// sufficiently. :(
for (size_t c = 0; c < C2; ++c) {
for (size_t r = 0; r < R1; ++r) {
T accum{0};
for (std::size_t c = 0; c < C2; ++c) {
for (std::size_t r = 0; r < R1; ++r) {
T accum {0};
for (size_t i = 0; i < R2; ++i)
for (std::size_t i = 0; i < RC; ++i)
accum += a[r][i] * b[i][c];
res[r][c] = accum;
@ -245,8 +324,8 @@ namespace util {
//-------------------------------------------------------------------------
template <
size_t R1, size_t C1,
size_t R2, size_t C2,
std::size_t R1, std::size_t C1,
std::size_t R2, std::size_t C2,
typename T
>
constexpr
@ -256,36 +335,128 @@ namespace util {
///////////////////////////////////////////////////////////////////////////
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
T
determinant (const matrix<Rows,Cols,T>&);
template <size_t Rows, size_t Cols, typename T>
//-------------------------------------------------------------------------
template <std::size_t Rows, std::size_t Cols, typename T>
matrix<Rows,Cols,T>
inverse (const matrix<Rows,Cols,T>&);
template <size_t Rows, size_t Cols, typename T>
//-------------------------------------------------------------------------
template <std::size_t Rows, std::size_t Cols, typename T>
matrix<Cols,Rows,T>
transposed (const matrix<Rows,Cols,T>&);
///////////////////////////////////////////////////////////////////////////
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
matrix<Rows,Cols,T>
abs (const matrix<Rows,Cols,T>&);
abs (const matrix<Rows,Cols,T> &src)
{
matrix<Rows,Cols,T> dst;
for (size_t r = 0; r < Rows; ++r)
dst[r] = abs (src[r]);
return dst;
}
template <size_t Rows, size_t Cols, typename T>
constexpr
T
sum (const matrix<Rows,Cols,T>&);
template <std::size_t Rows, std::size_t Cols, typename T>
constexpr T
sum (const matrix<Rows,Cols,T> &src)
{
util::vector<Rows,T> accum {};
for (size_t r = 0; r < Rows; ++r)
accum[r] = sum (src[r]);
return sum (accum);
}
///////////////////////////////////////////////////////////////////////////
#define MATRIX_ELEMENT_OP(OP) \
template <std::size_t Rows, std::size_t Cols, typename T> \
constexpr \
matrix<Rows,Cols,T> \
operator OP ( \
const matrix<Rows,Cols,T> &a, \
const matrix<Rows,Cols,T> &b) \
{ \
matrix<Rows,Cols,T> res {}; \
\
for (std::size_t i = 0; i < a.rows; ++i) \
for (std::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
///////////////////////////////////////////////////////////////////////////
#define MATRIX_SCALAR_OP(OP) \
template <std::size_t Rows, std::size_t Cols, typename T> \
constexpr \
matrix<Rows,Cols,T> \
operator OP (const matrix<Rows,Cols,T> &m, const T t) \
{ \
matrix<Rows,Cols,T> res {}; \
\
std::transform ( \
std::cbegin (m), \
std::cend (m), \
std::begin (res), \
[&t] (auto x) { return x OP t; } \
); \
\
return res; \
} \
\
\
template <std::size_t Rows, std::size_t Cols, typename T> \
constexpr \
matrix<Rows,Cols,T> \
operator OP (const T t, const matrix<Rows,Cols,T> &m) \
{ \
return m OP t; \
} \
\
\
template <std::size_t Rows, std::size_t Cols, typename T> \
constexpr \
matrix<Rows,Cols,T>& \
operator OP##= (matrix<Rows,Cols,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 <typename T> using matrix3 = matrix<3,3,T>;
template <typename T> using matrix4 = matrix<4,4,T>;
template <size_t Rows, size_t Cols> using matrixf = matrix<Rows,Cols,float>;
template <size_t Rows, size_t Cols> using matrixd = matrix<Rows,Cols,double>;
template <std::size_t Rows, std::size_t Cols> using matrixf = matrix<Rows,Cols,float>;
template <std::size_t Rows, std::size_t Cols> using matrixd = matrix<Rows,Cols,double>;
typedef matrix<2,2,float> matrix2f;
typedef matrix<2,2,double> matrix2d;
@ -298,10 +469,18 @@ namespace util {
///////////////////////////////////////////////////////////////////////////
template <size_t Rows, size_t Cols, typename T>
std::ostream& operator<< (std::ostream&, const matrix<Rows,Cols,T>&);
}
#include "matrix.ipp"
template <std::size_t Rows, std::size_t Cols, typename T>
std::ostream&
operator<< (std::ostream &os, const matrix<Rows,Cols,T> &m)
{
os << '[';
std::copy (
std::cbegin (m),
std::cend (m),
util::infix_iterator<decltype(m[0])> (os, ", ")
);
return os << ']';
}
};
#endif

View File

@ -1,165 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2011-2015 Danny Robson <danny@nerdcruft.net>
*/
#ifdef __UTIL_MATRIX_IPP
#error
#endif
#define __UTIL_MATRIX_IPP
///////////////////////////////////////////////////////////////////////////////
#define MATRIX_ELEMENT_OP(OP) \
template <size_t Rows, size_t Cols, typename T> \
constexpr \
util::matrix<Rows,Cols,T> \
util::operator OP ( \
const util::matrix<Rows,Cols,T> &a, \
const util::matrix<Rows,Cols,T> &b) \
{ \
util::matrix<Rows,Cols,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
///////////////////////////////////////////////////////////////////////////////
#define MATRIX_SCALAR_OP(OP) \
template <size_t Rows, size_t Cols, typename T> \
constexpr \
util::matrix<Rows,Cols,T> \
util::operator OP (const util::matrix<Rows,Cols,T> &m, const T t) \
{ \
util::matrix<Rows,Cols,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 Rows, size_t Cols, typename T> \
constexpr \
util::matrix<Rows,Cols,T> \
util::operator OP (const T t, const util::matrix<Rows,Cols,T> &m) \
{ \
return m OP t; \
} \
\
\
template <size_t Rows, size_t Cols, typename T> \
constexpr \
util::matrix<Rows,Cols,T>& \
util::operator OP##= (util::matrix<Rows,Cols,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 Rows, size_t Cols, typename T>
constexpr
util::matrix<Rows,Cols,T>
util::matrix<Rows,Cols,T>::zeroes (void)
{
return {0};
}
///////////////////////////////////////////////////////////////////////////////
template <size_t Rows, size_t Cols, typename T>
constexpr
util::matrix<Rows,Cols,T>
util::matrix<Rows,Cols,T>::identity (void)
{
static_assert (Rows == Cols);
auto m = zeroes ();
for (size_t i = 0; i < Rows; ++i)
m[i][i] = 1;
return m;
}
///////////////////////////////////////////////////////////////////////////////
template <size_t Rows, size_t Cols, typename T>
constexpr
bool
util::operator== (const matrix<Rows,Cols,T> &a, const matrix<Rows,Cols,T> &b)
{
return std::equal (std::cbegin (a), std::cend (a), std::cbegin (b));
}
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
constexpr
bool
util::operator!= (const matrix<Rows,Cols,T> &a, const matrix<Rows,Cols,T> &b)
{
return !(a == b);
}
///////////////////////////////////////////////////////////////////////////////
template <size_t Rows, size_t Cols, typename T>
util::matrix<Rows,Cols,T>
util::abs (const util::matrix<Rows,Cols,T> &src)
{
util::matrix<Rows,Cols,T> dst;
std::transform (std::cbegin (src), std::cend (src), std::begin (dst), util::abs<T>);
return dst;
}
///////////////////////////////////////////////////////////////////////////////
template <size_t Rows, size_t Cols, typename T>
constexpr
T
util::sum (const util::matrix<Rows, Cols,T> &src)
{
return sum (std::cbegin (src), std::cend (src));
}

View File

@ -20,7 +20,7 @@ using util::matrix;
///////////////////////////////////////////////////////////////////////////////
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
T
util::determinant (const matrix<Rows,Cols,T> &m)
{
@ -34,16 +34,16 @@ template double util::determinant (const matrix<2,2,double>&);
///////////////////////////////////////////////////////////////////////////////
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
matrix<Rows,Cols,T>
util::inverse (const matrix<Rows,Cols,T> &m)
{
static_assert (Rows == 2 && Cols == 2);
return matrix<2,2,T> {
m[1][1], -m[0][1],
-m[1][0], m[0][0]
} / determinant (m);
return matrix<2,2,T> {{
{ m[1][1], -m[0][1], },
{ -m[1][0], m[0][0], },
}} / determinant (m);
}

View File

@ -14,13 +14,13 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "./matrix.hpp"
#include "matrix.hpp"
using util::matrix;
///////////////////////////////////////////////////////////////////////////////
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
T
util::determinant (const matrix<Rows,Cols,T>& m)
{
@ -36,25 +36,25 @@ template double util::determinant (const matrix<3,3,double>&);
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
matrix<Rows,Cols,T>
util::inverse (const matrix<Rows,Cols,T> &m)
{
static_assert (Rows == 3 && Cols == 3);
return matrix<3,3,T> {
m[1][1] * m[2][2] - m[2][1] * m[1][2],
m[0][2] * m[2][1] - m[0][1] * m[2][2],
m[0][1] * m[1][2] - m[0][2] * m[1][1],
return matrix<3,3,T> {{
{ m[1][1] * m[2][2] - m[2][1] * m[1][2],
m[0][2] * m[2][1] - m[0][1] * m[2][2],
m[0][1] * m[1][2] - m[0][2] * m[1][1], },
m[1][2] * m[2][0] - m[1][0] * m[2][2],
m[0][0] * m[2][2] - m[0][2] * m[2][0],
m[1][0] * m[0][2] - m[0][0] * m[1][2],
{ m[1][2] * m[2][0] - m[1][0] * m[2][2],
m[0][0] * m[2][2] - m[0][2] * m[2][0],
m[1][0] * m[0][2] - m[0][0] * m[1][2], },
m[1][0] * m[2][1] - m[2][0] * m[1][1],
m[2][0] * m[0][1] - m[0][0] * m[2][1],
m[0][0] * m[1][1] - m[1][0] * m[0][1],
} / determinant (m);
{ m[1][0] * m[2][1] - m[2][0] * m[1][1],
m[2][0] * m[0][1] - m[0][0] * m[2][1],
m[0][0] * m[1][1] - m[1][0] * m[0][1], },
}} / determinant (m);
}
template util::matrix<3,3,float> util::inverse (const matrix<3,3,float>&);

View File

@ -20,7 +20,7 @@ using util::matrix;
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
T
util::determinant (const matrix<Rows,Cols,T> &m)
{
@ -45,30 +45,125 @@ template double util::determinant (const matrix<4,4,double>&);
//-----------------------------------------------------------------------------
template <size_t Rows, size_t Cols, typename T>
template <std::size_t Rows, std::size_t Cols, typename T>
matrix<Rows,Cols,T>
util::inverse (const matrix<Rows,Cols,T> &m)
{
static_assert (Rows == 4 && Cols == 4);
return matrix<4,4,T> {
m[1][2]*m[2][3]*m[3][1] - m[1][3]*m[2][2]*m[3][1] + m[1][3]*m[2][1]*m[3][2] - m[1][1]*m[2][3]*m[3][2] - m[1][2]*m[2][1]*m[3][3] + m[1][1]*m[2][2]*m[3][3],
m[0][3]*m[2][2]*m[3][1] - m[0][2]*m[2][3]*m[3][1] - m[0][3]*m[2][1]*m[3][2] + m[0][1]*m[2][3]*m[3][2] + m[0][2]*m[2][1]*m[3][3] - m[0][1]*m[2][2]*m[3][3],
m[0][2]*m[1][3]*m[3][1] - m[0][3]*m[1][2]*m[3][1] + m[0][3]*m[1][1]*m[3][2] - m[0][1]*m[1][3]*m[3][2] - m[0][2]*m[1][1]*m[3][3] + m[0][1]*m[1][2]*m[3][3],
m[0][3]*m[1][2]*m[2][1] - m[0][2]*m[1][3]*m[2][1] - m[0][3]*m[1][1]*m[2][2] + m[0][1]*m[1][3]*m[2][2] + m[0][2]*m[1][1]*m[2][3] - m[0][1]*m[1][2]*m[2][3],
m[1][3]*m[2][2]*m[3][0] - m[1][2]*m[2][3]*m[3][0] - m[1][3]*m[2][0]*m[3][2] + m[1][0]*m[2][3]*m[3][2] + m[1][2]*m[2][0]*m[3][3] - m[1][0]*m[2][2]*m[3][3],
m[0][2]*m[2][3]*m[3][0] - m[0][3]*m[2][2]*m[3][0] + m[0][3]*m[2][0]*m[3][2] - m[0][0]*m[2][3]*m[3][2] - m[0][2]*m[2][0]*m[3][3] + m[0][0]*m[2][2]*m[3][3],
m[0][3]*m[1][2]*m[3][0] - m[0][2]*m[1][3]*m[3][0] - m[0][3]*m[1][0]*m[3][2] + m[0][0]*m[1][3]*m[3][2] + m[0][2]*m[1][0]*m[3][3] - m[0][0]*m[1][2]*m[3][3],
m[0][2]*m[1][3]*m[2][0] - m[0][3]*m[1][2]*m[2][0] + m[0][3]*m[1][0]*m[2][2] - m[0][0]*m[1][3]*m[2][2] - m[0][2]*m[1][0]*m[2][3] + m[0][0]*m[1][2]*m[2][3],
m[1][1]*m[2][3]*m[3][0] - m[1][3]*m[2][1]*m[3][0] + m[1][3]*m[2][0]*m[3][1] - m[1][0]*m[2][3]*m[3][1] - m[1][1]*m[2][0]*m[3][3] + m[1][0]*m[2][1]*m[3][3],
m[0][3]*m[2][1]*m[3][0] - m[0][1]*m[2][3]*m[3][0] - m[0][3]*m[2][0]*m[3][1] + m[0][0]*m[2][3]*m[3][1] + m[0][1]*m[2][0]*m[3][3] - m[0][0]*m[2][1]*m[3][3],
m[0][1]*m[1][3]*m[3][0] - m[0][3]*m[1][1]*m[3][0] + m[0][3]*m[1][0]*m[3][1] - m[0][0]*m[1][3]*m[3][1] - m[0][1]*m[1][0]*m[3][3] + m[0][0]*m[1][1]*m[3][3],
m[0][3]*m[1][1]*m[2][0] - m[0][1]*m[1][3]*m[2][0] - m[0][3]*m[1][0]*m[2][1] + m[0][0]*m[1][3]*m[2][1] + m[0][1]*m[1][0]*m[2][3] - m[0][0]*m[1][1]*m[2][3],
m[1][2]*m[2][1]*m[3][0] - m[1][1]*m[2][2]*m[3][0] - m[1][2]*m[2][0]*m[3][1] + m[1][0]*m[2][2]*m[3][1] + m[1][1]*m[2][0]*m[3][2] - m[1][0]*m[2][1]*m[3][2],
m[0][1]*m[2][2]*m[3][0] - m[0][2]*m[2][1]*m[3][0] + m[0][2]*m[2][0]*m[3][1] - m[0][0]*m[2][2]*m[3][1] - m[0][1]*m[2][0]*m[3][2] + m[0][0]*m[2][1]*m[3][2],
m[0][2]*m[1][1]*m[3][0] - m[0][1]*m[1][2]*m[3][0] - m[0][2]*m[1][0]*m[3][1] + m[0][0]*m[1][2]*m[3][1] + m[0][1]*m[1][0]*m[3][2] - m[0][0]*m[1][1]*m[3][2],
m[0][1]*m[1][2]*m[2][0] - m[0][2]*m[1][1]*m[2][0] + m[0][2]*m[1][0]*m[2][1] - m[0][0]*m[1][2]*m[2][1] - m[0][1]*m[1][0]*m[2][2] + m[0][0]*m[1][1]*m[2][2],
} / determinant (m);
return matrix<4,4,T> {{
{ m[1][2]*m[2][3]*m[3][1]
-m[1][3]*m[2][2]*m[3][1]
+m[1][3]*m[2][1]*m[3][2]
-m[1][1]*m[2][3]*m[3][2]
-m[1][2]*m[2][1]*m[3][3]
+m[1][1]*m[2][2]*m[3][3],
m[0][3]*m[2][2]*m[3][1]
-m[0][2]*m[2][3]*m[3][1]
-m[0][3]*m[2][1]*m[3][2]
+m[0][1]*m[2][3]*m[3][2]
+m[0][2]*m[2][1]*m[3][3]
-m[0][1]*m[2][2]*m[3][3],
m[0][2]*m[1][3]*m[3][1]
-m[0][3]*m[1][2]*m[3][1]
+m[0][3]*m[1][1]*m[3][2]
-m[0][1]*m[1][3]*m[3][2]
-m[0][2]*m[1][1]*m[3][3]
+m[0][1]*m[1][2]*m[3][3],
m[0][3]*m[1][2]*m[2][1]
-m[0][2]*m[1][3]*m[2][1]
-m[0][3]*m[1][1]*m[2][2]
+m[0][1]*m[1][3]*m[2][2]
+m[0][2]*m[1][1]*m[2][3]
-m[0][1]*m[1][2]*m[2][3], },
{ m[1][3]*m[2][2]*m[3][0]
-m[1][2]*m[2][3]*m[3][0]
-m[1][3]*m[2][0]*m[3][2]
+m[1][0]*m[2][3]*m[3][2]
+m[1][2]*m[2][0]*m[3][3]
-m[1][0]*m[2][2]*m[3][3],
m[0][2]*m[2][3]*m[3][0]
-m[0][3]*m[2][2]*m[3][0]
+m[0][3]*m[2][0]*m[3][2]
-m[0][0]*m[2][3]*m[3][2]
-m[0][2]*m[2][0]*m[3][3]
+m[0][0]*m[2][2]*m[3][3],
m[0][3]*m[1][2]*m[3][0]
-m[0][2]*m[1][3]*m[3][0]
-m[0][3]*m[1][0]*m[3][2]
+m[0][0]*m[1][3]*m[3][2]
+m[0][2]*m[1][0]*m[3][3]
-m[0][0]*m[1][2]*m[3][3],
m[0][2]*m[1][3]*m[2][0]
-m[0][3]*m[1][2]*m[2][0]
+m[0][3]*m[1][0]*m[2][2]
-m[0][0]*m[1][3]*m[2][2]
-m[0][2]*m[1][0]*m[2][3]
+m[0][0]*m[1][2]*m[2][3], },
{ m[1][1]*m[2][3]*m[3][0]
-m[1][3]*m[2][1]*m[3][0]
+m[1][3]*m[2][0]*m[3][1]
-m[1][0]*m[2][3]*m[3][1]
-m[1][1]*m[2][0]*m[3][3]
+m[1][0]*m[2][1]*m[3][3],
m[0][3]*m[2][1]*m[3][0]
-m[0][1]*m[2][3]*m[3][0]
-m[0][3]*m[2][0]*m[3][1]
+m[0][0]*m[2][3]*m[3][1]
+m[0][1]*m[2][0]*m[3][3]
-m[0][0]*m[2][1]*m[3][3],
m[0][1]*m[1][3]*m[3][0]
-m[0][3]*m[1][1]*m[3][0]
+m[0][3]*m[1][0]*m[3][1]
-m[0][0]*m[1][3]*m[3][1]
-m[0][1]*m[1][0]*m[3][3]
+m[0][0]*m[1][1]*m[3][3],
m[0][3]*m[1][1]*m[2][0]
-m[0][1]*m[1][3]*m[2][0]
-m[0][3]*m[1][0]*m[2][1]
+m[0][0]*m[1][3]*m[2][1]
+m[0][1]*m[1][0]*m[2][3]
-m[0][0]*m[1][1]*m[2][3], },
{ m[1][2]*m[2][1]*m[3][0]
-m[1][1]*m[2][2]*m[3][0]
-m[1][2]*m[2][0]*m[3][1]
+m[1][0]*m[2][2]*m[3][1]
+m[1][1]*m[2][0]*m[3][2]
-m[1][0]*m[2][1]*m[3][2],
m[0][1]*m[2][2]*m[3][0]
-m[0][2]*m[2][1]*m[3][0]
+m[0][2]*m[2][0]*m[3][1]
-m[0][0]*m[2][2]*m[3][1]
-m[0][1]*m[2][0]*m[3][2]
+m[0][0]*m[2][1]*m[3][2],
m[0][2]*m[1][1]*m[3][0]
-m[0][1]*m[1][2]*m[3][0]
-m[0][2]*m[1][0]*m[3][1]
+m[0][0]*m[1][2]*m[3][1]
+m[0][1]*m[1][0]*m[3][2]
-m[0][0]*m[1][1]*m[3][2],
m[0][1]*m[1][2]*m[2][0]
-m[0][2]*m[1][1]*m[2][0]
+m[0][2]*m[1][0]*m[2][1]
-m[0][0]*m[1][2]*m[2][1]
-m[0][1]*m[1][0]*m[2][2]
+m[0][0]*m[1][1]*m[2][2], }
}} / determinant (m);
}
template util::matrix<4,4,float> util::inverse (const matrix<4,4,float>&);

View File

@ -14,14 +14,14 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "./circular.hpp"
#include "circular.hpp"
#include "../system.hpp"
#include "../../debug.hpp"
#include "../../except.hpp"
#include "../../maths.hpp"
#include "../../posix/except.hpp"
#include "../../raii.hpp"
#include "../../random.hpp"
#include "../system.hpp"
#include <unistd.h>
#include <sys/mman.h>
@ -54,7 +54,8 @@ tmpname (std::string &str, size_t length)
///////////////////////////////////////////////////////////////////////////////
circular::circular (size_t bytes)
template <typename ValueT>
circular<ValueT>::circular (size_t bytes)
{
bytes = max (bytes, sizeof (value_type));
bytes = round_up (bytes, pagesize ());
@ -84,14 +85,16 @@ circular::circular (size_t bytes)
// embiggen to the desired size
if (ftruncate (fd, bytes))
errno_error::throw_code ();
posix::error::throw_code ();
// pre-allocate a sufficiently large virtual memory block. it doesn't
// matter much what flags we use because we'll just be overwriting it
// shortly.
m_begin = reinterpret_cast<char*> (mmap (nullptr, bytes * 2, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
m_begin = reinterpret_cast<ValueT*> (
mmap (nullptr, bytes * 2, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)
);
if (MAP_FAILED == m_begin)
errno_error::throw_code ();
posix::error::throw_code ();
// preemptively setup an unmapping object in case the remapping fails
util::scoped_function unmapper ([this, bytes] (void) { munmap (m_begin, bytes); });
@ -101,11 +104,11 @@ circular::circular (size_t bytes)
auto prot = PROT_READ | PROT_WRITE;
auto flag = MAP_FIXED | MAP_SHARED;
m_begin = reinterpret_cast<char*> (mmap (m_begin, bytes, prot, flag, fd, 0));
m_end = reinterpret_cast<char*> (mmap (m_begin + bytes, bytes, prot, flag, fd, 0));
m_begin = reinterpret_cast<ValueT*> (mmap (m_begin, bytes, prot, flag, fd, 0));
m_end = reinterpret_cast<ValueT*> (mmap (m_begin + bytes, bytes, prot, flag, fd, 0));
if (m_begin == MAP_FAILED || m_end == MAP_FAILED)
errno_error::throw_code ();
posix::error::throw_code ();
// all went well, disarm the failsafe
unmapper.clear ();
@ -113,7 +116,8 @@ circular::circular (size_t bytes)
//-----------------------------------------------------------------------------
circular::~circular ()
template <typename ValueT>
circular<ValueT>::~circular ()
{
auto res = munmap (m_begin, 2 * (m_end - m_begin));
(void)res;
@ -122,24 +126,61 @@ circular::~circular ()
///////////////////////////////////////////////////////////////////////////////
char*
circular::begin (void)&
template <typename ValueT>
ValueT*
circular<ValueT>::begin (void)&
{
return m_begin;
}
//-----------------------------------------------------------------------------
char*
circular::end (void)&
template <typename ValueT>
ValueT*
circular<ValueT>::end (void)&
{
return m_end;
}
///////////////////////////////////////////////////////////////////////////////
template <typename ValueT>
size_t
circular::size (void) const
circular<ValueT>::size (void) const
{
return m_end - m_begin;
}
//-----------------------------------------------------------------------------
template <typename ValueT>
typename circular<ValueT>::iterator
circular<ValueT>::constrain (iterator cursor)
{
CHECK_LIMIT (cursor, m_begin, m_begin + 2 * size ());
return m_begin + (cursor - m_begin) % size ();
}
//-----------------------------------------------------------------------------
template <typename ValueT>
util::view<typename circular<ValueT>::iterator>
circular<ValueT>::constrain (util::view<iterator> window)
{
CHECK_LIMIT (window.begin (), m_begin, m_begin + 2 * size ());
CHECK_LIMIT (window.end (), m_begin, m_begin + 2 * size ());
auto first = window.begin ();
auto last = first + window.size ();
util::view res { first, last };
CHECK_EQ (res.size (), window.size ());
CHECK_LE (res.begin (), res.end ());
return res;
}
///////////////////////////////////////////////////////////////////////////////
template class util::memory::buffer::circular<char>;
template class util::memory::buffer::circular<uint8_t>;

View File

@ -17,15 +17,20 @@
#ifndef __UTIL_MEMORY_BUFFER_CIRCULAR_HPP
#define __UTIL_MEMORY_BUFFER_CIRCULAR_HPP
#include "../../view.hpp"
#include <cstddef>
namespace util::memory::buffer {
// buffer size is advisory and will likely depend on page size. the user
// must check the size after creation if this field is important for
// their usage.
template <typename ValueT>
class circular {
public:
using value_type = char;
using value_type = ValueT;
using iterator = value_type*;
using const_iterator = const value_type*;
explicit circular (size_t bytes);
~circular ();
@ -35,19 +40,26 @@ namespace util::memory::buffer {
circular& operator= (const circular&) = delete;
circular& operator= (circular&&) = delete;
char& operator[] (size_t)&;
const char& operator[] (size_t) const&;
value_type& operator[] (size_t)&;
const value_type& operator[] (size_t) const&;
char* begin (void)&;
char* end (void)&;
iterator begin (void)&;
iterator end (void)&;
const char* begin (void) const&;
const char* end (void) const&;
const_iterator begin (void) const&;
const_iterator end (void) const&;
size_t size (void) const;
/// rebases the pointer so that it points to within the first
/// repetition of the data buffer.
iterator constrain (iterator);
/// rebases a pair of pointers so they fall within a contiguous span of
/// the data buffer.
util::view<iterator> constrain (util::view<iterator>);
private:
char *m_begin, *m_end;
value_type *m_begin, *m_end;
};
}

View File

@ -14,13 +14,13 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "./paged.hpp"
#include "paged.hpp"
#include "../system.hpp"
#include "../../except.hpp"
#include "../../cast.hpp"
#include "../../maths.hpp"
#include "../../pointer.hpp"
#include "../../cast.hpp"
#include "../../posix/except.hpp"
#include "../system.hpp"
#include <sys/mman.h>
@ -37,7 +37,7 @@ paged::paged (size_t bytes, size_t _window):
);
if (m_begin == MAP_FAILED)
errno_error::throw_code ();
posix::error::throw_code ();
// remap the initial window with read/write permissions
m_cursor = m_begin + round_up (min (m_window, bytes), pagesize ());
@ -45,7 +45,7 @@ paged::paged (size_t bytes, size_t _window):
m_cursor - m_begin,
PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0))
errno_error::throw_code ();
posix::error::throw_code ();
// record the nominal end address
m_end = m_begin + round_up (bytes, pagesize ());
@ -110,7 +110,7 @@ paged::commit (char *cursor)
PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0))
errno_error::throw_code ();
posix::error::throw_code ();
m_cursor = cursor;
}
@ -137,7 +137,7 @@ paged::release (char *desired)
PROT_NONE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0))
errno_error::throw_code ();
posix::error::throw_code ();
m_cursor = desired;
}

View File

@ -14,7 +14,7 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "./deleter.hpp"
#include "deleter.hpp"
using util::memory::owner_deleter;

View File

@ -14,10 +14,10 @@
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
*/
#include "./system.hpp"
#include "system.hpp"
#include "../except.hpp"
#include "../cast.hpp"
#include "../posix/except.hpp"
#include <unistd.h>
@ -28,11 +28,7 @@ util::memory::pagesize (void)
static size_t val;
if (!val) {
auto res = sysconf (_SC_PAGE_SIZE);
if (res == -1)
errno_error::throw_code ();
val = sign_cast<unsigned long> (res);
val = sign_cast<unsigned long> (posix::error::try_value (sysconf (_SC_PAGE_SIZE)));
}
return val;

View File

@ -14,7 +14,9 @@
* Copyright 2017 Danny Robson <danny@nerdcruft.net>
*/
#include "./parse.hpp"
#include "parse.hpp"
#include "cast.hpp"
#include <cstdlib>
#include <stdexcept>
@ -69,9 +71,9 @@ c_fparse (const char *first, const char *last)
#define C_PARSE(T, KLASS) \
template <> \
T \
util::parse<T> (const char *first, const char *last) \
util::parse<T> (util::view<const char *> str) \
{ \
return c_ ## KLASS ## parse<T> (first, last); \
return c_ ## KLASS ## parse<T> (std::cbegin (str), std::cend (str)); \
}
@ -84,3 +86,12 @@ C_PARSE(unsigned long long, i)
C_PARSE(float, f)
C_PARSE(double, f)
C_PARSE(long double, f)
template <>
int
util::parse<int> (util::view<const char*> str)
{
auto intermediate = util::parse<long> (str);
return trunc_cast<int> (intermediate);
}

View File

@ -17,6 +17,8 @@
#ifndef CRUFT_UTIL_PARSE_HPP
#define CRUFT_UTIL_PARSE_HPP
#include "view.hpp"
#include <cstring>
#include <string>
#include <iterator>
@ -28,16 +30,14 @@ namespace util {
///
/// throws std::invalid_argument when the type cannot be parsed.
template <typename T>
T
parse (const char *first, const char *last);
T parse (util::view<const char *>);
//-------------------------------------------------------------------------
template <typename T>
T
parse (const char *str)
T parse (const char *str)
{
return parse<T> (str, str + strlen (str));
return parse<T> (make_view (str));
}
@ -46,7 +46,7 @@ namespace util {
T
parse (const std::string &str)
{
return parse<T> (std::cbegin (str), std::cend (str));
return parse<T> (make_view (str));
}
}

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