Move and add some template metaprogramming classes

This commit is contained in:
Vinnie Falco
2013-09-19 11:55:34 -07:00
parent 2a164f0165
commit 72fc42b60c
13 changed files with 497 additions and 167 deletions

View File

@@ -22,9 +22,164 @@
namespace beast
{
namespace parse
{
/** Require and consume the specified character from the input.
@return `true` if the character matched.
*/
bool expect (std::istream& is, char v)
{
char c;
if (is.get(c) && v == c)
return true;
is.unget();
is.setstate (std::ios_base::failbit);
return false;
}
namespace detail
{
/** Used to disambiguate 8-bit integers from characters. */
template <typename IntType>
struct integer_holder
{
IntType* pi;
explicit integer_holder (IntType& i)
: pi (&i)
{
}
template <typename OtherIntType>
IntType& operator= (OtherIntType o) const
{
*pi = o;
return *pi;
}
};
/** Parse 8-bit unsigned integer. */
std::istream& operator>> (std::istream& is, integer_holder <uint8> const& i)
{
uint16 v;
is >> v;
if (! (v>=0 && v<=255))
{
is.setstate (std::ios_base::failbit);
return is;
}
i = uint8(v);
return is;
}
}
/** Free function for template argument deduction. */
template <typename IntType>
detail::integer_holder <IntType> integer (IntType& i)
{
return detail::integer_holder <IntType> (i);
}
}
/** Parse IPv4 address. */
std::istream& operator>> (std::istream &is, IPEndpoint::V4& addr)
{
uint8 octets [4];
is >> parse::integer (octets [0]);
for (int i = 1; i < 4; ++i)
{
if (!is || !parse::expect (is, '.'))
return is;
is >> parse::integer (octets [i]);
if (!is)
return is;
}
addr = IPEndpoint::V4 (octets[0], octets[1], octets[2], octets[3]);
return is;
}
/** Parse an IPEndpoint.
@note Currently only IPv4 addresses are supported.
*/
inline std::istream& operator>> (std::istream &is, IPEndpoint& ep)
{
IPEndpoint::V4 v4;
is >> v4;
if (is.fail())
return is;
if (is.rdbuf()->in_avail()>0)
{
char c;
is.get(c);
if (c != ':')
{
is.unget();
ep = IPEndpoint (v4);
return is;
}
uint16 port;
is >> port;
if (is.fail())
return is;
ep = IPEndpoint (v4, port);
}
else
{
ep = IPEndpoint (v4);
}
return is;
}
//------------------------------------------------------------------------------
class IPEndpointTests : public UnitTest
{
public:
bool parse (char const* text, IPEndpoint& ep)
{
std::string input (text);
std::istringstream stream (input);
stream >> ep;
return !stream.fail();
}
void shouldPass (char const* text)
{
IPEndpoint ep;
expect (parse (text, ep));
expect (ep.to_string() == std::string(text));
}
void shouldFail (char const* text)
{
IPEndpoint ep;
unexpected (parse (text, ep));
}
void testParse ()
{
beginTestCase ("parse");
shouldPass ("0.0.0.0");
shouldPass ("192.168.0.1");
shouldPass ("168.127.149.132");
shouldPass ("168.127.149.132:80");
shouldPass ("168.127.149.132:54321");
shouldFail ("");
shouldFail ("255");
shouldFail ("512");
shouldFail ("1.2.3.256");
shouldFail ("1.2.3:80");
}
void testPrint ()
{
beginTestCase ("addresses");
@@ -36,7 +191,7 @@ public:
expect ( ep.isPrivate());
expect (!ep.isBroadcast());
expect (!ep.isMulticast());
expect (!ep.isLoopback());
expect ( ep.isLoopback());
expect (ep.to_string() == "127.0.0.1:80");
ep = IPEndpoint::V4(10,0,0,1);
@@ -60,6 +215,7 @@ public:
void runTest ()
{
testPrint();
testParse();
}
IPEndpointTests () : UnitTest ("IPEndpoint", "beast")