On 12/10/2015 2:49 PM, Alf P. Steinbach wrote:
>...
> The enclosed header and unit test is my attempt to deal with these
> issues, as part of the core language support I posted about earlier.
> This is a work in progress, so in particular the unit testing is just
> direct use of Microsoft's framework for Visual Studio. The goal is to
> compile and test this also with g++; discussion and/or advice for that
> is very welcome, plus of course, discussion and/or advice for the header
> itself is very welcome.
<file "basic_types.hpp">
#pragma once
// core_language_support/basic_types.hpp
// Copyright © Alf P. Steinbach 2015. Boost Software License 1.0.
#include <p/cppx/tmp/Type_set.hpp> // cppx::Type_set
#include <p/cppx/tmp/sfinae.hpp> // cppx::If_
#include <p/cppx/core_language_support/static_assert.h> //
CPPX_STATIC_ASSERT
#include <assert.h> // assert
#include <limits> // std::numeric_limits
#include <limits.h> // CHAR_BIT
#include <stddef.h> // size_t
#include <type_traits> // std::conditional_t
// For a discussion of Syschar see the article "Portable String Literals
in C++" by
// Alf P. Steinbach, ACCU Overload journal August 2013; the article is
available online
// at <url:
http://accu.org/index.php/journals/1842>. Eessentially it's
the natural
// Unicode character endcoding unit for the system at hand, strictly
typed as an enum.
// As an enum it's compatible with std::basic_string short buffer
optimization.
#ifdef _WIN32
# define CPPX_SYSCHAR_IS_WIDE 1 // Implies UTF-16 encoding.
#else
# define CPPX_SYSCHAR_IS_WIDE 0 // Impliies UTF-8 encoding.
#endif
namespace progrock{ namespace cppx{
using std::conditional_t;
using std::is_integral;
using std::make_unsigned_t;
using std::numeric_limits;
// With some compilers/options the UB of overflowing a signed
integer is real, or
// at least causes annoying and troublesome sillywarnings, so:
template< class Result, class Arg
, class Enabled_ = If_< is_integral<Result> >
>
auto wrap_to( Arg const v )
-> Result
{
CPPX_STATIC_ASSERT( numeric_limits<Result>::is_modulo );
// Additionally assumes that there are no trap representation bits.
using Unsigned = make_unsigned_t<Result>;
Unsigned const wrapped = static_cast<Unsigned>( v );
return reinterpret_cast<Result const&>( wrapped );
}
using Byte = unsigned char;
int const bits_per_byte = CHAR_BIT;
using Index = ptrdiff_t;
using Size = Index;
using Ascii = enum: char // Strongly typed ASCII.
{
nul = '\0',
bel = '\a', // alarm / bell, ^G, 7
bs = '\b', // backspace, ^H, 8
tab = '\t', // tab, ^I, 9
lf = '\n', // linefeed / newline, ^J, 10
vt = '\v', // vertical tab, ^K, 11
ff = '\f', // formfeed, ^L, 12
cr = '\r', // carriage return, ^M, 13
xon = 17, // device control 1 / xon, ^Q, 17
xoff = 19, // device control 3 / xoff, ^S, 19, "stop"
esc = 27, // escape
space = 32,
del = 127 // delete
};
using Utf8 = enum: Byte {}; // Strongly typed UTF-8.
using Utf16 = enum: char16_t {}; // Strongly typed UTF-16.
using Utf32 = enum: char32_t {}; // Strongly typed UTF-32.
bool constexpr syschar_is_wide = !!CPPX_SYSCHAR_IS_WIDE;
bool constexpr syschar_is_byte = not syschar_is_wide;
using Syschar_base = conditional_t< syschar_is_wide, wchar_t, char >;
using Syschar = enum: Syschar_base {};
inline
auto is_ascii( char const code )
-> bool
{ return Byte( code ) <= Byte( Ascii::del ); }
template< class Iter >
auto is_ascii( Iter const first, Iter const after )
{
for( Iter it = first; it != after; ++it )
{
if( not is_ascii( *it ) )
{
return false;
}
}
return true;
}
// Types that can ordinarily be assumed to represent character
encoding values:
using Character_types = Type_set <
// System-dependent encoding:
Syschar, char, wchar_t,
// Fixed encoding:
Ascii, Utf8, Utf16, Utf32, char16_t, char32_t
>;
// Types that can ordinarily be assumed to represent UTF-8 encoded
text.
//
// In Windows no built-in C++ type can be assumed to represent
UTF-8 encoded
// text, but in Unix-land "char" is usually UTF-8.
using Basic_utf8_types = Type_set<Utf8>;
using Utf8_types = conditional_t<
/* if */ syschar_is_wide,
/* then */ Basic_utf8_types, // Windows.
/* else */ Union_< Basic_utf8_types, char > // Unix-land.
>;
// Types that can ordinarily be assumed to represent UTF-16 encoded
text:
using Basic_utf16_types = Type_set< Utf16, char16_t >;
using Utf16_types = conditional_t<
/* if */ syschar_is_wide, // Implies Windows & 16 bits
wchar_t
/* then */ Union_< Basic_utf16_types, Type_set< Syschar,
wchar_t > >,
/* else */ Basic_utf16_types
>;
// Types that can ordinarily be assumed to represent UTF-32 encoded
text:
using Basic_utf32_types = Type_set< Utf32, char32_t >;
using Utf32_types = conditional_t<
/* if */ syschar_is_wide, // Implies Windows & 16 bits
wchar_t
/* then */ Basic_utf32_types,
/* else */ Union_< Basic_utf32_types, wchar_t >
>;
}} // namespace progrock::cppx
</file>
<file "basic_types_test.cpp">
#include <p/cppx/core_language_support/basic_types.hpp>
#include <iterator> // std::begin, std::end
#include "ms_unit_test.hpp"
namespace ut = Microsoft::VisualStudio::CppUnitTestFramework;
namespace cppx = progrock::cppx;
using std::begin;
using std::end;
namespace cppx_test
{
TEST_CLASS(basic_types)
{
public:
TEST_METHOD( wrap_to )
{
unsigned const u = unsigned( -12345 );
int const i = cppx::wrap_to<int>( u );
ut::Assert::AreEqual( u, unsigned( i ), L"Test 100" );
}
TEST_METHOD( is_ascii__char )
{
using cppx::wrap_to;
ut::Assert::AreEqual( true, cppx::is_ascii(
wrap_to<char>( 0 ) ), L"Test 100" );
ut::Assert::AreEqual( true, cppx::is_ascii(
wrap_to<char>( 127 ) ), L"Test 200" );
ut::Assert::AreEqual( false, cppx::is_ascii(
wrap_to<char>( -1 ) ), L"Test 300" );
ut::Assert::AreEqual( false, cppx::is_ascii(
wrap_to<char>( 128 ) ), L"Test 400" );
ut::Assert::AreEqual( false, cppx::is_ascii(
wrap_to<char>( 255 ) ), L"Test 500" );
}
TEST_METHOD( is_ascii__range )
{
char const empty = 0;
char const blah[] = "Blah";
char const norw[] = "Blåbærsyltetøy";
ut::Assert::AreEqual( true, cppx::is_ascii( &empty,
&empty ), L"Test 000" );
ut::Assert::AreEqual( true, cppx::is_ascii( begin( blah
), end( blah ) ), L"Test 100" );
ut::Assert::AreEqual( false, cppx::is_ascii( begin( norw
), end( norw ) ), L"Test 200" );
}
};
} // namespace cppx_test
</file>
Cheers,
- Alf