Commit 74bf54b9 authored by Kenton Varda's avatar Kenton Varda

Define new KJ constants for min/max integer values and inf/nan, then remove all…

Define new KJ constants for min/max integer values and inf/nan, then remove all use of numeric_limits.
parent 4878663f
......@@ -364,8 +364,7 @@ private:
// =======================================================================================
inline ReadLimiter::ReadLimiter()
// I didn't want to #include <limits> just for this one lousy constant.
: limit(0x7fffffffffffffffllu) {}
: limit(kj::maxValue) {}
inline ReadLimiter::ReadLimiter(WordCount64 limit): limit(limit / WORDS) {}
......
......@@ -41,7 +41,6 @@
#include <sys/wait.h>
#include <capnp/serialize.h>
#include <capnp/serialize-packed.h>
#include <limits>
#include <errno.h>
#include <stdlib.h>
......@@ -608,9 +607,8 @@ private:
// Since this is a debug tool, lift the usual security limits. Worse case is the process
// crashes or has to be killed.
ReaderOptions options;
options.nestingLimit = std::numeric_limits<decltype(options.nestingLimit)>::max() >> 1;
options.traversalLimitInWords =
std::numeric_limits<decltype(options.traversalLimitInWords)>::max();
options.nestingLimit = kj::maxValue;
options.traversalLimitInWords = kj::maxValue;
MessageReaderType reader(input, options);
kj::String text;
......
......@@ -27,7 +27,6 @@
#include <kj/arena.h>
#include <set>
#include <map>
#include <limits>
namespace capnp {
namespace compiler {
......@@ -440,7 +439,7 @@ public:
uint addData(uint lgSize) override {
addVoid();
uint bestSize = std::numeric_limits<uint>::max();
uint bestSize = kj::maxValue;
kj::Maybe<uint> bestLocation = nullptr;
for (uint i = 0; i < parent.dataLocations.size(); i++) {
......@@ -1661,19 +1660,19 @@ kj::Maybe<Orphan<DynamicValue>> ValueTranslator::compileValue(
if (value < 0) {
int64_t minValue = 1;
switch (type.which()) {
case schema::Type::INT8: minValue = std::numeric_limits<int8_t>::min(); break;
case schema::Type::INT16: minValue = std::numeric_limits<int16_t>::min(); break;
case schema::Type::INT32: minValue = std::numeric_limits<int32_t>::min(); break;
case schema::Type::INT64: minValue = std::numeric_limits<int64_t>::min(); break;
case schema::Type::UINT8: minValue = std::numeric_limits<uint8_t>::min(); break;
case schema::Type::UINT16: minValue = std::numeric_limits<uint16_t>::min(); break;
case schema::Type::UINT32: minValue = std::numeric_limits<uint32_t>::min(); break;
case schema::Type::UINT64: minValue = std::numeric_limits<uint64_t>::min(); break;
case schema::Type::INT8: minValue = (int8_t)kj::minValue; break;
case schema::Type::INT16: minValue = (int16_t)kj::minValue; break;
case schema::Type::INT32: minValue = (int32_t)kj::minValue; break;
case schema::Type::INT64: minValue = (int64_t)kj::minValue; break;
case schema::Type::UINT8: minValue = (uint8_t)kj::minValue; break;
case schema::Type::UINT16: minValue = (uint16_t)kj::minValue; break;
case schema::Type::UINT32: minValue = (uint32_t)kj::minValue; break;
case schema::Type::UINT64: minValue = (uint64_t)kj::minValue; break;
case schema::Type::FLOAT32:
case schema::Type::FLOAT64:
// Any integer is acceptable.
minValue = std::numeric_limits<int64_t>::min();
minValue = (int64_t)kj::minValue;
break;
default: break;
......@@ -1693,19 +1692,19 @@ kj::Maybe<Orphan<DynamicValue>> ValueTranslator::compileValue(
case DynamicValue::UINT: {
uint64_t maxValue = 0;
switch (type.which()) {
case schema::Type::INT8: maxValue = std::numeric_limits<int8_t>::max(); break;
case schema::Type::INT16: maxValue = std::numeric_limits<int16_t>::max(); break;
case schema::Type::INT32: maxValue = std::numeric_limits<int32_t>::max(); break;
case schema::Type::INT64: maxValue = std::numeric_limits<int64_t>::max(); break;
case schema::Type::UINT8: maxValue = std::numeric_limits<uint8_t>::max(); break;
case schema::Type::UINT16: maxValue = std::numeric_limits<uint16_t>::max(); break;
case schema::Type::UINT32: maxValue = std::numeric_limits<uint32_t>::max(); break;
case schema::Type::UINT64: maxValue = std::numeric_limits<uint64_t>::max(); break;
case schema::Type::INT8: maxValue = (int8_t)kj::maxValue; break;
case schema::Type::INT16: maxValue = (int16_t)kj::maxValue; break;
case schema::Type::INT32: maxValue = (int32_t)kj::maxValue; break;
case schema::Type::INT64: maxValue = (int64_t)kj::maxValue; break;
case schema::Type::UINT8: maxValue = (uint8_t)kj::maxValue; break;
case schema::Type::UINT16: maxValue = (uint16_t)kj::maxValue; break;
case schema::Type::UINT32: maxValue = (uint32_t)kj::maxValue; break;
case schema::Type::UINT64: maxValue = (uint64_t)kj::maxValue; break;
case schema::Type::FLOAT32:
case schema::Type::FLOAT64:
// Any integer is acceptable.
maxValue = std::numeric_limits<uint64_t>::max();
maxValue = (uint64_t)kj::maxValue;
break;
default: break;
......@@ -1813,9 +1812,9 @@ Orphan<DynamicValue> ValueTranslator::compileValueInner(
} else if (id == "false") {
return false;
} else if (id == "nan") {
return std::numeric_limits<double>::quiet_NaN();
return kj::nan();
} else if (id == "inf") {
return std::numeric_limits<double>::infinity();
return kj::inf();
}
}
}
......@@ -1833,7 +1832,7 @@ Orphan<DynamicValue> ValueTranslator::compileValueInner(
case ValueExpression::NEGATIVE_INT: {
uint64_t nValue = src.getNegativeInt();
if (nValue > (std::numeric_limits<uint64_t>::max() >> 1) + 1) {
if (nValue > ((uint64_t)kj::maxValue >> 1) + 1) {
errorReporter.addErrorOn(src, "Integer is too big to be negative.");
return nullptr;
} else {
......
......@@ -29,7 +29,6 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits>
namespace capnp {
namespace compiler {
......@@ -544,7 +543,7 @@ CapnpParser::CapnpParser(Orphanage orphanageParam, const ErrorReporter& errorRep
-> Orphan<ValueExpression> {
auto result = orphanage.newOrphan<ValueExpression>();
auto builder = result.get();
builder.setFloat(-std::numeric_limits<double>::infinity());
builder.setFloat(-kj::inf());
initLocation(location, builder);
return result;
}),
......
......@@ -1661,16 +1661,16 @@ TEST(Encoding, Constants) {
List<float>::Reader listReader = test::TestConstants::FLOAT32_LIST_CONST;
ASSERT_EQ(4u, listReader.size());
EXPECT_EQ(5555.5f, listReader[0]);
EXPECT_EQ(std::numeric_limits<float>::infinity(), listReader[1]);
EXPECT_EQ(-std::numeric_limits<float>::infinity(), listReader[2]);
EXPECT_EQ(kj::inf(), listReader[1]);
EXPECT_EQ(-kj::inf(), listReader[2]);
EXPECT_TRUE(listReader[3] != listReader[3]);
}
{
List<double>::Reader listReader = test::TestConstants::FLOAT64_LIST_CONST;
ASSERT_EQ(4u, listReader.size());
EXPECT_EQ(7777.75, listReader[0]);
EXPECT_EQ(std::numeric_limits<double>::infinity(), listReader[1]);
EXPECT_EQ(-std::numeric_limits<double>::infinity(), listReader[2]);
EXPECT_EQ(kj::inf(), listReader[1]);
EXPECT_EQ(-kj::inf(), listReader[2]);
EXPECT_TRUE(listReader[3] != listReader[3]);
}
checkList(*test::TestConstants::TEXT_LIST_CONST, {"plugh", "xyzzy", "thud"});
......
......@@ -27,7 +27,6 @@
#include "arena.h"
#include "capability.h"
#include <string.h>
#include <limits>
#include <stdlib.h>
namespace capnp {
......@@ -462,7 +461,7 @@ struct WireHelpers {
reinterpret_cast<const WirePointer*>(ptr + tag->structRef.dataSize.get()),
tag->structRef.dataSize.get() * BITS_PER_WORD,
tag->structRef.ptrCount.get(),
0 * BITS, std::numeric_limits<int>::max()));
0 * BITS, kj::maxValue));
// no break: treat like struct pointer
case WirePointer::STRUCT: {
......@@ -548,7 +547,7 @@ struct WireHelpers {
// -----------------------------------------------------------------
static WordCount64 totalSize(SegmentReader* segment, const WirePointer* ref, uint nestingLimit) {
static WordCount64 totalSize(SegmentReader* segment, const WirePointer* ref, int nestingLimit) {
// Compute the total size of the object pointed to, not counting far pointer overhead.
if (ref->isNull()) {
......@@ -2173,7 +2172,7 @@ void PointerBuilder::setList(const ListReader& value) {
kj::Own<const ClientHook> PointerBuilder::getCapability() {
return WireHelpers::readCapabilityPointer(
segment, pointer, std::numeric_limits<int>::max());
segment, pointer, kj::maxValue);
}
void PointerBuilder::setCapability(kj::Own<const ClientHook>&& cap) {
......@@ -2206,7 +2205,7 @@ void PointerBuilder::copyFrom(PointerReader other) {
}
PointerReader PointerBuilder::asReader() const {
return PointerReader(segment, pointer, std::numeric_limits<int>::max());
return PointerReader(segment, pointer, kj::maxValue);
}
BuilderArena* PointerBuilder::getArena() const {
......@@ -2373,7 +2372,7 @@ void StructBuilder::copyContentFrom(StructReader other) {
StructReader StructBuilder::asReader() const {
return StructReader(segment, data, pointers,
dataSize, pointerCount, bit0Offset, std::numeric_limits<int>::max());
dataSize, pointerCount, bit0Offset, kj::maxValue);
}
BuilderArena* StructBuilder::getArena() {
......@@ -2451,7 +2450,7 @@ StructBuilder ListBuilder::getStructElement(ElementCount index) {
ListReader ListBuilder::asReader() const {
return ListReader(segment, ptr, elementCount, step, structDataSize, structPointerCount,
std::numeric_limits<int>::max());
kj::maxValue);
}
BuilderArena* ListBuilder::getArena() {
......@@ -2668,19 +2667,19 @@ Data::Builder OrphanBuilder::asData() {
StructReader OrphanBuilder::asStructReader(StructSize size) const {
KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr));
return WireHelpers::readStructPointer(
segment, tagAsPtr(), location, nullptr, std::numeric_limits<int>::max());
segment, tagAsPtr(), location, nullptr, kj::maxValue);
}
ListReader OrphanBuilder::asListReader(FieldSize elementSize) const {
KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr));
return WireHelpers::readListPointer(
segment, tagAsPtr(), location, nullptr, elementSize, std::numeric_limits<int>::max());
segment, tagAsPtr(), location, nullptr, elementSize, kj::maxValue);
}
kj::Own<const ClientHook> OrphanBuilder::asCapability() const {
KJ_DASSERT(tagAsPtr()->isNull() == (location == nullptr));
return WireHelpers::readCapabilityPointer(
segment, tagAsPtr(), location, std::numeric_limits<int>::max());
segment, tagAsPtr(), location, kj::maxValue);
}
Text::Reader OrphanBuilder::asTextReader() const {
......
......@@ -69,7 +69,7 @@ struct ReaderOptions {
// but probably at least prevents easy exploitation while also avoiding causing problems in most
// typical cases.
uint nestingLimit = 64;
int nestingLimit = 64;
// Limits how deeply-nested a message structure can be, e.g. structs containing other structs or
// lists of structs.
//
......
......@@ -35,13 +35,13 @@ namespace {
class TestPipe: public kj::BufferedInputStream, public kj::OutputStream {
public:
TestPipe()
: preferredReadSize(std::numeric_limits<size_t>::max()), readPos(0) {}
: preferredReadSize(kj::maxValue), readPos(0) {}
explicit TestPipe(size_t preferredReadSize)
: preferredReadSize(preferredReadSize), readPos(0) {}
~TestPipe() {}
const std::string& getData() { return data; }
void resetRead(size_t preferredReadSize = std::numeric_limits<size_t>::max()) {
void resetRead(size_t preferredReadSize = kj::maxValue) {
readPos = 0;
this->preferredReadSize = preferredReadSize;
}
......@@ -50,7 +50,7 @@ public:
return readPos == data.size();
}
void clear(size_t preferredReadSize = std::numeric_limits<size_t>::max()) {
void clear(size_t preferredReadSize = kj::maxValue) {
resetRead(preferredReadSize);
data.clear();
}
......
......@@ -67,7 +67,7 @@ private:
class TestPipe: public kj::BufferedInputStream, public kj::OutputStream {
public:
TestPipe()
: preferredReadSize(std::numeric_limits<size_t>::max()), readPos(0) {}
: preferredReadSize(kj::maxValue), readPos(0) {}
explicit TestPipe(size_t preferredReadSize)
: preferredReadSize(preferredReadSize), readPos(0) {}
~TestPipe() {}
......@@ -76,7 +76,7 @@ public:
std::string getUnreadData() { return data.substr(readPos); }
std::string::size_type getReadPos() { return readPos; }
void resetRead(size_t preferredReadSize = std::numeric_limits<size_t>::max()) {
void resetRead(size_t preferredReadSize = kj::maxValue) {
readPos = 0;
this->preferredReadSize = preferredReadSize;
}
......@@ -85,7 +85,7 @@ public:
return readPos == data.size();
}
void clear(size_t preferredReadSize = std::numeric_limits<size_t>::max()) {
void clear(size_t preferredReadSize = kj::maxValue) {
resetRead(preferredReadSize);
data.clear();
}
......
......@@ -103,14 +103,8 @@ void genericInitTestMessage(Builder builder) {
builder.setUInt16List({33333u, 44444u});
builder.setUInt32List({3333333333u});
builder.setUInt64List({11111111111111111111ull});
builder.setFloat32List({5555.5,
std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::quiet_NaN()});
builder.setFloat64List({7777.75,
std::numeric_limits<double>::infinity(),
-std::numeric_limits<double>::infinity(),
std::numeric_limits<double>::quiet_NaN()});
builder.setFloat32List({5555.5, kj::inf(), -kj::inf(), kj::nan()});
builder.setFloat64List({7777.75, kj::inf(), -kj::inf(), kj::nan()});
builder.setTextList({"plugh", "xyzzy", "thud"});
builder.setDataList({data("oops"), data("exhausted"), data("rfc3092")});
{
......@@ -195,14 +189,8 @@ void dynamicInitTestMessage(DynamicStruct::Builder builder) {
builder.set("uInt16List", {33333u, 44444u});
builder.set("uInt32List", {3333333333u});
builder.set("uInt64List", {11111111111111111111ull});
builder.set("float32List", {5555.5,
std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::quiet_NaN()});
builder.set("float64List", {7777.75,
std::numeric_limits<double>::infinity(),
-std::numeric_limits<double>::infinity(),
std::numeric_limits<double>::quiet_NaN()});
builder.set("float32List", {5555.5, kj::inf(), -kj::inf(), kj::nan()});
builder.set("float64List", {7777.75, kj::inf(), -kj::inf(), kj::nan()});
builder.set("textList", {"plugh", "xyzzy", "thud"});
builder.set("dataList", {data("oops"), data("exhausted"), data("rfc3092")});
{
......@@ -296,16 +284,16 @@ void genericCheckTestMessage(Reader reader) {
auto listReader = reader.getFloat32List();
ASSERT_EQ(4u, listReader.size());
EXPECT_EQ(5555.5f, listReader[0]);
EXPECT_EQ(std::numeric_limits<float>::infinity(), listReader[1]);
EXPECT_EQ(-std::numeric_limits<float>::infinity(), listReader[2]);
EXPECT_EQ(kj::inf(), listReader[1]);
EXPECT_EQ(-kj::inf(), listReader[2]);
EXPECT_TRUE(isNaN(listReader[3]));
}
{
auto listReader = reader.getFloat64List();
ASSERT_EQ(4u, listReader.size());
EXPECT_EQ(7777.75, listReader[0]);
EXPECT_EQ(std::numeric_limits<double>::infinity(), listReader[1]);
EXPECT_EQ(-std::numeric_limits<double>::infinity(), listReader[2]);
EXPECT_EQ(kj::inf(), listReader[1]);
EXPECT_EQ(-kj::inf(), listReader[2]);
EXPECT_TRUE(isNaN(listReader[3]));
}
checkList(reader.getTextList(), {"plugh", "xyzzy", "thud"});
......@@ -420,16 +408,16 @@ void dynamicCheckTestMessage(Reader reader) {
auto listReader = reader.get("float32List").as<DynamicList>();
ASSERT_EQ(4u, listReader.size());
EXPECT_EQ(5555.5f, listReader[0].as<float>());
EXPECT_EQ(std::numeric_limits<float>::infinity(), listReader[1].as<float>());
EXPECT_EQ(-std::numeric_limits<float>::infinity(), listReader[2].as<float>());
EXPECT_EQ(kj::inf(), listReader[1].as<float>());
EXPECT_EQ(-kj::inf(), listReader[2].as<float>());
EXPECT_TRUE(isNaN(listReader[3].as<float>()));
}
{
auto listReader = reader.get("float64List").as<DynamicList>();
ASSERT_EQ(4u, listReader.size());
EXPECT_EQ(7777.75, listReader[0].as<double>());
EXPECT_EQ(std::numeric_limits<double>::infinity(), listReader[1].as<double>());
EXPECT_EQ(-std::numeric_limits<double>::infinity(), listReader[2].as<double>());
EXPECT_EQ(kj::inf(), listReader[1].as<double>());
EXPECT_EQ(-kj::inf(), listReader[2].as<double>());
EXPECT_TRUE(isNaN(listReader[3].as<double>()));
}
checkList<Text>(reader.get("textList"), {"plugh", "xyzzy", "thud"});
......
......@@ -25,7 +25,6 @@
#include "debug.h"
#include <setjmp.h>
#include <errno.h>
#include <limits>
namespace kj {
......@@ -169,7 +168,7 @@ public:
}
}
void cleanup(uint count = std::numeric_limits<uint>::max()) {
void cleanup(uint count = maxValue) {
// Goes through the list (up to a max of `count` items) and removes any that are no longer
// relevant.
......
......@@ -262,6 +262,32 @@ TEST(Common, MinMax) {
EXPECT_EQ(1234567890123456789ll, kj::max('a', 1234567890123456789ll));
}
TEST(Common, MinMaxValue) {
EXPECT_EQ(0x7f, int8_t(maxValue));
EXPECT_EQ(0xffu, uint8_t(maxValue));
EXPECT_EQ(0x7fff, int16_t(maxValue));
EXPECT_EQ(0xffffu, uint16_t(maxValue));
EXPECT_EQ(0x7fffffff, int32_t(maxValue));
EXPECT_EQ(0xffffffffu, uint32_t(maxValue));
EXPECT_EQ(0x7fffffffffffffffll, int64_t(maxValue));
EXPECT_EQ(0xffffffffffffffffull, uint64_t(maxValue));
EXPECT_EQ(-0x80, int8_t(minValue));
EXPECT_EQ(0, uint8_t(minValue));
EXPECT_EQ(-0x8000, int16_t(minValue));
EXPECT_EQ(0, uint16_t(minValue));
EXPECT_EQ(-0x80000000, int32_t(minValue));
EXPECT_EQ(0, uint32_t(minValue));
EXPECT_EQ(-0x8000000000000000ll, int64_t(minValue));
EXPECT_EQ(0, uint64_t(minValue));
double f = inf();
EXPECT_TRUE(f * 2 == f);
f = nan();
EXPECT_FALSE(f == f);
}
TEST(Common, Defer) {
uint i = 0;
uint j = 1;
......
......@@ -369,6 +369,69 @@ inline constexpr size_t size(T&& arr) { return arr.size(); }
// Returns the size of the parameter, whether the parameter is a regular C array or a container
// with a `.size()` method.
class MaxValue_ {
private:
template <typename T>
inline constexpr T maxSigned() const {
return (1ull << (sizeof(T) * 8 - 1)) - 1;
}
template <typename T>
inline constexpr T maxUnsigned() const {
return ~static_cast<T>(0u);
}
public:
#define _kJ_HANDLE_TYPE(T) \
inline constexpr operator signed T() const { return MaxValue_::maxSigned < signed T>(); } \
inline constexpr operator unsigned T() const { return MaxValue_::maxUnsigned<unsigned T>(); }
_kJ_HANDLE_TYPE(char)
_kJ_HANDLE_TYPE(short)
_kJ_HANDLE_TYPE(int)
_kJ_HANDLE_TYPE(long)
_kJ_HANDLE_TYPE(long long)
#undef _kJ_HANDLE_TYPE
};
class MinValue_ {
private:
template <typename T>
inline constexpr T minSigned() const {
return 1ull << (sizeof(T) * 8 - 1);
}
template <typename T>
inline constexpr T minUnsigned() const {
return 0u;
}
public:
#define _kJ_HANDLE_TYPE(T) \
inline constexpr operator signed T() const { return MinValue_::minSigned < signed T>(); } \
inline constexpr operator unsigned T() const { return MinValue_::minUnsigned<unsigned T>(); }
_kJ_HANDLE_TYPE(char)
_kJ_HANDLE_TYPE(short)
_kJ_HANDLE_TYPE(int)
_kJ_HANDLE_TYPE(long)
_kJ_HANDLE_TYPE(long long)
#undef _kJ_HANDLE_TYPE
};
static constexpr MaxValue_ maxValue = MaxValue_();
// A special constant which, when cast to an integer type, takes on the maximum possible value of
// that type. This is useful to use as e.g. a parameter to a function because it will be robust
// in the face of changes to the parameter's type.
//
// `char` is not supported, but `signed char` and `unsigned char` are.
static constexpr MinValue_ minValue = MinValue_();
// A special constant which, when cast to an integer type, takes on the minimum possible value
// of that type. This is useful to use as e.g. a parameter to a function because it will be robust
// in the face of changes to the parameter's type.
//
// `char` is not supported, but `signed char` and `unsigned char` are.
inline double inf() { return 1.0 / 0.0; }
inline double nan() { return 0.0 / 0.0; }
// =======================================================================================
// Useful fake containers
......
......@@ -25,7 +25,6 @@
#include "debug.h"
#include <stdio.h>
#include <float.h>
#include <limits>
#include <errno.h>
#include <stdlib.h>
......@@ -217,10 +216,10 @@ char* DoubleToBuffer(double value, char* buffer) {
// this assert.
static_assert(DBL_DIG < 20, "DBL_DIG is too big.");
if (value == std::numeric_limits<double>::infinity()) {
if (value == inf()) {
strcpy(buffer, "inf");
return buffer;
} else if (value == -std::numeric_limits<double>::infinity()) {
} else if (value == -inf()) {
strcpy(buffer, "-inf");
return buffer;
} else if (IsNaN(value)) {
......@@ -273,10 +272,10 @@ char* FloatToBuffer(float value, char* buffer) {
// this assert.
static_assert(FLT_DIG < 10, "FLT_DIG is too big");
if (value == std::numeric_limits<double>::infinity()) {
if (value == inf()) {
strcpy(buffer, "inf");
return buffer;
} else if (value == -std::numeric_limits<double>::infinity()) {
} else if (value == -inf()) {
strcpy(buffer, "-inf");
return buffer;
} else if (IsNaN(value)) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment