Add an internal ASSERT macro

This macro has some advantages over the standard library one:
 - It prints the place where the macro was triggered
 - It "references" the condition even in Release to avoid warnings
 - In release, if possible, it gives compiler hints

It is basically is stripped down version of the ASSERT macros I wrote
for the Daemon engine in src/common/Assert.h

This commit also removes the stray "backend" namespaces for common/
code.
This commit is contained in:
Corentin Wallez
2017-07-10 13:46:05 -04:00
committed by Corentin Wallez
parent bd0594bab8
commit fd589f3919
37 changed files with 612 additions and 485 deletions

22
src/common/Assert.cpp Normal file
View File

@@ -0,0 +1,22 @@
// Copyright 2017 The NXT Authors
//
// 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.
#include "common/Assert.h"
#include <iostream>
void HandleAssertionFailure(const char* file, const char* function, int line, const char* condition) {
std::cerr << "Assertion failure at " << file << ":" << line << " (" << function << "): " << condition << std::endl;
NXT_BREAKPOINT();
}

74
src/common/Assert.h Normal file
View File

@@ -0,0 +1,74 @@
// Copyright 2017 The NXT Authors
//
// 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.
#ifndef COMMON_ASSERT_H_
#define COMMON_ASSERT_H_
#include "common/Compiler.h"
void HandleAssertionFailure(const char* file, const char* function, int line, const char* condition);
/*
* NXT asserts to be used instead of the regular C stdlib assert function (if you don't
* use assert yet, you should start now!). In debug ASSERT(condition) will trigger an error,
* otherwise in release it does nothing at runtime.
*
* In case of name clashes (with for example a testing library), you can define the
* NXT_SKIP_ASSERT_SHORTHANDS to only define the NXT_ prefixed macros.
*
* These asserts feature:
* - Logging of the error with file, line and function information.
* - Breaking in the debugger when an assert is triggered and a debugger is attached.
* - Use the assert information to help the compiler optimizer in release builds.
*/
// MSVC triggers a warning in /W4 for do {} while(0). SDL worked around this by using
// // (0,0) and points out that it looks like an owl face.
#if defined(_MSC_VER)
#define NXT_ASSERT_LOOP_CONDITION (0,0)
#else
#define NXT_ASSERT_LOOP_CONDITION (0)
#endif
// NXT_ASSERT_CALLSITE_HELPER generates the actual assert code. In Debug it does what you would
// expect of an assert and in release it tries to give hints to make the compiler generate better code.
#if defined(NXT_ENABLE_ASSERTS)
#define NXT_ASSERT_CALLSITE_HELPER(file, func, line, condition) \
do { \
if (!(condition)) { \
HandleAssertionFailure(file, func, line, #condition); \
} \
} while(NXT_ASSERT_LOOP_CONDITION)
#else
#if defined(_MSC_VER)
#define NXT_ASSERT_CALLSITE_HELPER(file, func, line, condition) \
__assume(condition)
#elif defined(__clang__) && defined(__builtin_assume)
#define NXT_ASSERT_CALLSITE_HELPER(file, func, line, condition) \
__builtin_assume(condition)
#else
#define NXT_ASSERT_CALLSITE_HELPER(file, func, line, condition) \
do { \
(void) sizeof(condition); \
} while(NXT_ASSERT_LOOP_CONDITION)
#endif
#endif
#define NXT_ASSERT(condition) NXT_ASSERT_CALLSITE_HELPER(__FILE__, __func__, __LINE__, condition)
#if !defined(NXT_SKIP_ASSERT_SHORTHANDS)
#define ASSERT NXT_ASSERT
#endif
#endif // COMMON_ASSERT_H_

View File

@@ -15,123 +15,118 @@
#ifndef COMMON_BITSETITERATOR_H_
#define COMMON_BITSETITERATOR_H_
#include "common/Assert.h"
#include "common/Math.h"
#include <cassert>
#include <bitset>
#include <limits>
#define ASSERT assert
// This is ANGLE's BitSetIterator class with a customizable return type
// TODO(cwallez@chromium.org): it could be optimized, in particular when N <= 64
namespace backend {
template <typename T>
T roundUp(const T value, const T alignment) {
auto temp = value + alignment - static_cast<T>(1);
return temp - temp % alignment;
}
template <typename T>
T roundUp(const T value, const T alignment) {
auto temp = value + alignment - static_cast<T>(1);
return temp - temp % alignment;
}
template <size_t N, typename T>
class BitSetIterator final {
public:
BitSetIterator(const std::bitset<N>& bitset);
BitSetIterator(const BitSetIterator& other);
BitSetIterator &operator=(const BitSetIterator& other);
template <size_t N, typename T>
class BitSetIterator final {
public:
BitSetIterator(const std::bitset<N>& bitset);
BitSetIterator(const BitSetIterator& other);
BitSetIterator &operator=(const BitSetIterator& other);
class Iterator final {
public:
Iterator(const std::bitset<N>& bits);
Iterator& operator++();
class Iterator final {
public:
Iterator(const std::bitset<N>& bits);
Iterator& operator++();
bool operator==(const Iterator& other) const;
bool operator!=(const Iterator& other) const;
T operator*() const { return static_cast<T>(mCurrentBit); }
bool operator==(const Iterator& other) const;
bool operator!=(const Iterator& other) const;
T operator*() const { return static_cast<T>(mCurrentBit); }
private:
unsigned long getNextBit();
private:
unsigned long getNextBit();
static const size_t BitsPerWord = sizeof(uint32_t) * 8;
std::bitset<N> mBits;
unsigned long mCurrentBit;
unsigned long mOffset;
};
static const size_t BitsPerWord = sizeof(uint32_t) * 8;
std::bitset<N> mBits;
unsigned long mCurrentBit;
unsigned long mOffset;
};
Iterator begin() const { return Iterator(mBits); }
Iterator end() const { return Iterator(std::bitset<N>(0)); }
Iterator begin() const { return Iterator(mBits); }
Iterator end() const { return Iterator(std::bitset<N>(0)); }
private:
const std::bitset<N> mBits;
};
private:
const std::bitset<N> mBits;
};
template <size_t N, typename T>
BitSetIterator<N, T>::BitSetIterator(const std::bitset<N>& bitset)
: mBits(bitset) {
}
template <size_t N, typename T>
BitSetIterator<N, T>::BitSetIterator(const std::bitset<N>& bitset)
: mBits(bitset) {
}
template <size_t N, typename T>
BitSetIterator<N, T>::BitSetIterator(const BitSetIterator& other)
: mBits(other.mBits) {
}
template <size_t N, typename T>
BitSetIterator<N, T>::BitSetIterator(const BitSetIterator& other)
: mBits(other.mBits) {
}
template <size_t N, typename T>
BitSetIterator<N, T>& BitSetIterator<N, T>::operator=(const BitSetIterator& other) {
mBits = other.mBits;
return *this;
}
template <size_t N, typename T>
BitSetIterator<N, T>& BitSetIterator<N, T>::operator=(const BitSetIterator& other) {
mBits = other.mBits;
return *this;
}
template <size_t N, typename T>
BitSetIterator<N, T>::Iterator::Iterator(const std::bitset<N>& bits)
: mBits(bits), mCurrentBit(0), mOffset(0) {
if (bits.any()) {
mCurrentBit = getNextBit();
} else {
mOffset = static_cast<unsigned long>(roundUp(N, BitsPerWord));
}
}
template <size_t N, typename T>
typename BitSetIterator<N, T>::Iterator& BitSetIterator<N, T>::Iterator::operator++() {
ASSERT(mBits.any());
mBits.set(mCurrentBit - mOffset, 0);
template <size_t N, typename T>
BitSetIterator<N, T>::Iterator::Iterator(const std::bitset<N>& bits)
: mBits(bits), mCurrentBit(0), mOffset(0) {
if (bits.any()) {
mCurrentBit = getNextBit();
return *this;
} else {
mOffset = static_cast<unsigned long>(roundUp(N, BitsPerWord));
}
}
template <size_t N, typename T>
bool BitSetIterator<N, T>::Iterator::operator==(const Iterator& other) const {
return mOffset == other.mOffset && mBits == other.mBits;
}
template <size_t N, typename T>
typename BitSetIterator<N, T>::Iterator& BitSetIterator<N, T>::Iterator::operator++() {
NXT_ASSERT(mBits.any());
mBits.set(mCurrentBit - mOffset, 0);
mCurrentBit = getNextBit();
return *this;
}
template <size_t N, typename T>
bool BitSetIterator<N, T>::Iterator::operator!=(const Iterator& other) const {
return !(*this == other);
}
template <size_t N, typename T>
bool BitSetIterator<N, T>::Iterator::operator==(const Iterator& other) const {
return mOffset == other.mOffset && mBits == other.mBits;
}
template <size_t N, typename T>
unsigned long BitSetIterator<N, T>::Iterator::getNextBit() {
static std::bitset<N> wordMask(std::numeric_limits<uint32_t>::max());
template <size_t N, typename T>
bool BitSetIterator<N, T>::Iterator::operator!=(const Iterator& other) const {
return !(*this == other);
}
while (mOffset < N) {
uint32_t wordBits = (mBits & wordMask).to_ulong();
if (wordBits != 0ul) {
return ScanForward(wordBits) + mOffset;
}
template <size_t N, typename T>
unsigned long BitSetIterator<N, T>::Iterator::getNextBit() {
static std::bitset<N> wordMask(std::numeric_limits<uint32_t>::max());
mBits >>= BitsPerWord;
mOffset += BitsPerWord;
while (mOffset < N) {
uint32_t wordBits = (mBits & wordMask).to_ulong();
if (wordBits != 0ul) {
return ScanForward(wordBits) + mOffset;
}
return 0;
}
// Helper to avoid needing to specify the template parameter size
template <size_t N>
BitSetIterator<N, uint32_t> IterateBitSet(const std::bitset<N>& bitset) {
return BitSetIterator<N, uint32_t>(bitset);
mBits >>= BitsPerWord;
mOffset += BitsPerWord;
}
return 0;
}
// Helper to avoid needing to specify the template parameter size
template <size_t N>
BitSetIterator<N, uint32_t> IterateBitSet(const std::bitset<N>& bitset) {
return BitSetIterator<N, uint32_t>(bitset);
}
#endif // COMMON_BITSETITERATOR_H_

View File

@@ -15,7 +15,10 @@
set(COMMON_DIR ${CMAKE_CURRENT_SOURCE_DIR})
list(APPEND COMMON_SOURCES
${COMMON_DIR}/Assert.cpp
${COMMON_DIR}/Assert.h
${COMMON_DIR}/BitSetIterator.h
${COMMON_DIR}/Compiler.h
${COMMON_DIR}/Math.cpp
${COMMON_DIR}/Math.h
${COMMON_DIR}/Serial.h

39
src/common/Compiler.h Normal file
View File

@@ -0,0 +1,39 @@
// Copyright 2017 The NXT Authors
//
// 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.
#ifndef COMMON_COMPILER_H_
#define COMMON_COMPILER_H_
// Defines macros for compiler-specific functionality
// - NXT_BREAKPOINT(): Raises an exception and breaks in the debugger
// Clang and GCC
#ifdef __GNUC__
#if defined(__i386__) || defined(__x86_64__)
#define NXT_BREAKPOINT() __asm__ __volatile__("int $3\n\t")
#else
#error "Implement BREAKPOINT on your platform"
#endif
// MSVC
#elif defined(_MSC_VER)
extern void __cdecl __debugbreak(void);
#define NXT_BREAKPOINT() __debugbreak()
#else
#error "Unsupported compiler"
#endif
#endif // COMMON_COMPILER_H_

View File

@@ -14,53 +14,48 @@
#include "common/Math.h"
#include "common/Assert.h"
#if defined(_WIN32) || defined(_WIN64)
#include <intrin.h>
#endif
#include <cassert>
#define ASSERT assert
namespace backend {
uint32_t ScanForward(uint32_t bits) {
ASSERT(bits != 0);
#if defined(_WIN32) || defined(_WIN64)
unsigned long firstBitIndex = 0ul;
unsigned char ret = _BitScanForward(&firstBitIndex, bits);
ASSERT(ret != 0);
return firstBitIndex;
#else
return static_cast<unsigned long>(__builtin_ctz(bits));
#endif
}
uint32_t Log2(uint32_t value) {
ASSERT(value != 0);
#if defined(_WIN32) || defined(_WIN64)
unsigned long firstBitIndex = 0ul;
unsigned char ret = _BitScanReverse(&firstBitIndex, value);
ASSERT(ret != 0);
return firstBitIndex;
#else
return 31 - __builtin_clz(value);
#endif
}
bool IsPowerOfTwo(size_t n) {
ASSERT(n != 0);
return (n & (n - 1)) == 0;
}
bool IsAligned(const void* ptr, size_t alignment) {
ASSERT(IsPowerOfTwo(alignment));
ASSERT(alignment != 0);
return (reinterpret_cast<intptr_t>(ptr) & (alignment - 1)) == 0;
}
void* AlignVoidPtr(void* ptr, size_t alignment) {
ASSERT(alignment != 0);
return reinterpret_cast<void*>((reinterpret_cast<intptr_t>(ptr) + (alignment - 1)) & ~(alignment - 1));
}
uint32_t ScanForward(uint32_t bits) {
ASSERT(bits != 0);
#if defined(_WIN32) || defined(_WIN64)
unsigned long firstBitIndex = 0ul;
unsigned char ret = _BitScanForward(&firstBitIndex, bits);
ASSERT(ret != 0);
return firstBitIndex;
#else
return static_cast<unsigned long>(__builtin_ctz(bits));
#endif
}
uint32_t Log2(uint32_t value) {
ASSERT(value != 0);
#if defined(_WIN32) || defined(_WIN64)
unsigned long firstBitIndex = 0ul;
unsigned char ret = _BitScanReverse(&firstBitIndex, value);
ASSERT(ret != 0);
return firstBitIndex;
#else
return 31 - __builtin_clz(value);
#endif
}
bool IsPowerOfTwo(size_t n) {
ASSERT(n != 0);
return (n & (n - 1)) == 0;
}
bool IsAligned(const void* ptr, size_t alignment) {
ASSERT(IsPowerOfTwo(alignment));
ASSERT(alignment != 0);
return (reinterpret_cast<intptr_t>(ptr) & (alignment - 1)) == 0;
}
void* AlignVoidPtr(void* ptr, size_t alignment) {
ASSERT(alignment != 0);
return reinterpret_cast<void*>((reinterpret_cast<intptr_t>(ptr) + (alignment - 1)) & ~(alignment - 1));
}

View File

@@ -18,26 +18,22 @@
#include <cstddef>
#include <cstdint>
namespace backend {
// The following are not valid for 0
uint32_t ScanForward(uint32_t bits);
uint32_t Log2(uint32_t value);
bool IsPowerOfTwo(size_t n);
// The following are not valid for 0
uint32_t ScanForward(uint32_t bits);
uint32_t Log2(uint32_t value);
bool IsPowerOfTwo(size_t n);
bool IsAligned(const void* ptr, size_t alignment);
void* AlignVoidPtr(void* ptr, size_t alignment);
bool IsAligned(const void* ptr, size_t alignment);
void* AlignVoidPtr(void* ptr, size_t alignment);
template<typename T>
T* Align(T* ptr, size_t alignment) {
return reinterpret_cast<T*>(AlignVoidPtr(ptr, alignment));
}
template<typename T>
const T* Align(const T* ptr, size_t alignment) {
return reinterpret_cast<const T*>(AlignVoidPtr(const_cast<T*>(ptr), alignment));
}
template<typename T>
T* Align(T* ptr, size_t alignment) {
return reinterpret_cast<T*>(AlignVoidPtr(ptr, alignment));
}
template<typename T>
const T* Align(const T* ptr, size_t alignment) {
return reinterpret_cast<const T*>(AlignVoidPtr(const_cast<T*>(ptr), alignment));
}
#endif // COMMON_MATH_H_

View File

@@ -15,322 +15,317 @@
#ifndef COMMON_SERIALQUEUE_H_
#define COMMON_SERIALQUEUE_H_
#include "common/Assert.h"
#include "common/Serial.h"
#include <cassert>
#include <cstdint>
#include <vector>
#define ASSERT assert
template<typename T>
class SerialQueue {
private:
using SerialPair = std::pair<Serial, std::vector<T>>;
using Storage = std::vector<SerialPair>;
using StorageIterator = typename Storage::iterator;
using ConstStorageIterator = typename Storage::const_iterator;
namespace backend {
public:
class Iterator {
public:
Iterator(StorageIterator start);
Iterator& operator++();
template<typename T>
class SerialQueue {
private:
using SerialPair = std::pair<Serial, std::vector<T>>;
using Storage = std::vector<SerialPair>;
using StorageIterator = typename Storage::iterator;
using ConstStorageIterator = typename Storage::const_iterator;
bool operator==(const Iterator& other) const;
bool operator!=(const Iterator& other) const;
T& operator*() const;
public:
class Iterator {
public:
Iterator(StorageIterator start);
Iterator& operator++();
private:
StorageIterator storageIterator;
// Special case the serialIterator when it should be equal to storageIterator.begin()
// otherwise we could ask storageIterator.begin() when storageIterator is storage.end()
// which is invalid. storageIterator.begin() is tagged with a nullptr.
T* serialIterator;
};
bool operator==(const Iterator& other) const;
bool operator!=(const Iterator& other) const;
T& operator*() const;
class ConstIterator {
public:
ConstIterator(ConstStorageIterator start);
ConstIterator& operator++();
private:
StorageIterator storageIterator;
// Special case the serialIterator when it should be equal to storageIterator.begin()
// otherwise we could ask storageIterator.begin() when storageIterator is storage.end()
// which is invalid. storageIterator.begin() is tagged with a nullptr.
T* serialIterator;
};
bool operator==(const ConstIterator& other) const;
bool operator!=(const ConstIterator& other) const;
const T& operator*() const;
class ConstIterator {
public:
ConstIterator(ConstStorageIterator start);
ConstIterator& operator++();
private:
ConstStorageIterator storageIterator;
const T* serialIterator;
};
bool operator==(const ConstIterator& other) const;
bool operator!=(const ConstIterator& other) const;
const T& operator*() const;
class BeginEnd {
public:
BeginEnd(StorageIterator start, StorageIterator end);
private:
ConstStorageIterator storageIterator;
const T* serialIterator;
};
Iterator begin() const;
Iterator end() const;
class BeginEnd {
public:
BeginEnd(StorageIterator start, StorageIterator end);
private:
StorageIterator startIt;
StorageIterator endIt;
};
Iterator begin() const;
Iterator end() const;
class ConstBeginEnd {
public:
ConstBeginEnd(ConstStorageIterator start, ConstStorageIterator end);
private:
StorageIterator startIt;
StorageIterator endIt;
};
ConstIterator begin() const;
ConstIterator end() const;
class ConstBeginEnd {
public:
ConstBeginEnd(ConstStorageIterator start, ConstStorageIterator end);
private:
ConstStorageIterator startIt;
ConstStorageIterator endIt;
};
ConstIterator begin() const;
ConstIterator end() const;
// The serial must be given in (not strictly) increasing order.
void Enqueue(const T& value, Serial serial);
void Enqueue(T&& value, Serial serial);
void Enqueue(const std::vector<T>& values, Serial serial);
void Enqueue(std::vector<T>&& values, Serial serial);
private:
ConstStorageIterator startIt;
ConstStorageIterator endIt;
};
bool Empty() const;
// The serial must be given in (not strictly) increasing order.
void Enqueue(const T& value, Serial serial);
void Enqueue(T&& value, Serial serial);
void Enqueue(const std::vector<T>& values, Serial serial);
void Enqueue(std::vector<T>&& values, Serial serial);
// The UpTo variants of Iterate and Clear affect all values associated to a serial
// that is smaller OR EQUAL to the given serial. Iterating is done like so:
// for (const T& value : queue.IterateAll()) { stuff(T); }
ConstBeginEnd IterateAll() const;
ConstBeginEnd IterateUpTo(Serial serial) const;
BeginEnd IterateAll();
BeginEnd IterateUpTo(Serial serial);
bool Empty() const;
void Clear();
void ClearUpTo(Serial serial);
// The UpTo variants of Iterate and Clear affect all values associated to a serial
// that is smaller OR EQUAL to the given serial. Iterating is done like so:
// for (const T& value : queue.IterateAll()) { stuff(T); }
ConstBeginEnd IterateAll() const;
ConstBeginEnd IterateUpTo(Serial serial) const;
BeginEnd IterateAll();
BeginEnd IterateUpTo(Serial serial);
Serial FirstSerial() const;
void Clear();
void ClearUpTo(Serial serial);
private:
// Returns the first StorageIterator that a serial bigger than serial.
ConstStorageIterator FindUpTo(Serial serial) const;
StorageIterator FindUpTo(Serial serial);
Storage storage;
};
Serial FirstSerial() const;
// SerialQueue
private:
// Returns the first StorageIterator that a serial bigger than serial.
ConstStorageIterator FindUpTo(Serial serial) const;
StorageIterator FindUpTo(Serial serial);
Storage storage;
};
template<typename T>
void SerialQueue<T>::Enqueue(const T& value, Serial serial) {
NXT_ASSERT(Empty() || storage.back().first <= serial);
// SerialQueue
if (Empty() || storage.back().first < serial) {
storage.emplace_back(SerialPair(serial, {}));
}
storage.back().second.emplace_back(value);
}
template<typename T>
void SerialQueue<T>::Enqueue(const T& value, Serial serial) {
ASSERT(Empty() || storage.back().first <= serial);
template<typename T>
void SerialQueue<T>::Enqueue(T&& value, Serial serial) {
NXT_ASSERT(Empty() || storage.back().first <= serial);
if (Empty() || storage.back().first < serial) {
storage.emplace_back(SerialPair(serial, {}));
}
storage.back().second.emplace_back(value);
if (Empty() || storage.back().first < serial) {
storage.emplace_back(SerialPair(serial, {}));
}
storage.back().second.emplace_back(value);
}
template<typename T>
void SerialQueue<T>::Enqueue(const std::vector<T>& values, Serial serial) {
NXT_ASSERT(values.size() > 0);
NXT_ASSERT(Empty() || storage.back().first <= serial);
storage.emplace_back(SerialPair(serial, {values}));
}
template<typename T>
void SerialQueue<T>::Enqueue(std::vector<T>&& values, Serial serial) {
NXT_ASSERT(values.size() > 0);
NXT_ASSERT(Empty() || storage.back().first <= serial);
storage.emplace_back(SerialPair(serial, {values}));
}
template<typename T>
bool SerialQueue<T>::Empty() const {
return storage.empty();
}
template<typename T>
typename SerialQueue<T>::ConstBeginEnd SerialQueue<T>::IterateAll() const {
return {storage.begin(), storage.end()};
}
template<typename T>
typename SerialQueue<T>::ConstBeginEnd SerialQueue<T>::IterateUpTo(Serial serial) const {
return {storage.begin(), FindUpTo(serial)};
}
template<typename T>
typename SerialQueue<T>::BeginEnd SerialQueue<T>::IterateAll() {
return {storage.begin(), storage.end()};
}
template<typename T>
typename SerialQueue<T>::BeginEnd SerialQueue<T>::IterateUpTo(Serial serial) {
return {storage.begin(), FindUpTo(serial)};
}
template<typename T>
void SerialQueue<T>::Clear() {
storage.clear();
}
template<typename T>
void SerialQueue<T>::ClearUpTo(Serial serial) {
storage.erase(storage.begin(), FindUpTo(serial));
}
template<typename T>
Serial SerialQueue<T>::FirstSerial() const {
NXT_ASSERT(!Empty());
return storage.front().first;
}
template<typename T>
typename SerialQueue<T>::ConstStorageIterator SerialQueue<T>::FindUpTo(Serial serial) const {
auto it = storage.begin();
while (it != storage.end() && it->first <= serial) {
it ++;
}
return it;
}
template<typename T>
typename SerialQueue<T>::StorageIterator SerialQueue<T>::FindUpTo(Serial serial) {
auto it = storage.begin();
while (it != storage.end() && it->first <= serial) {
it ++;
}
return it;
}
// SerialQueue::BeginEnd
template<typename T>
SerialQueue<T>::BeginEnd::BeginEnd(typename SerialQueue<T>::StorageIterator start, typename SerialQueue<T>::StorageIterator end)
: startIt(start), endIt(end) {
}
template<typename T>
typename SerialQueue<T>::Iterator SerialQueue<T>::BeginEnd::begin() const {
return {startIt};
}
template<typename T>
typename SerialQueue<T>::Iterator SerialQueue<T>::BeginEnd::end() const {
return {endIt};
}
// SerialQueue::Iterator
template<typename T>
SerialQueue<T>::Iterator::Iterator(typename SerialQueue<T>::StorageIterator start)
: storageIterator(start), serialIterator(nullptr) {
}
template<typename T>
typename SerialQueue<T>::Iterator& SerialQueue<T>::Iterator::operator++() {
T* vectorData = storageIterator->second.data();
if (serialIterator == nullptr) {
serialIterator = vectorData + 1;
} else {
serialIterator ++;
}
template<typename T>
void SerialQueue<T>::Enqueue(T&& value, Serial serial) {
ASSERT(Empty() || storage.back().first <= serial);
if (Empty() || storage.back().first < serial) {
storage.emplace_back(SerialPair(serial, {}));
}
storage.back().second.emplace_back(value);
if (serialIterator >= vectorData + storageIterator->second.size()) {
serialIterator = nullptr;
storageIterator ++;
}
template<typename T>
void SerialQueue<T>::Enqueue(const std::vector<T>& values, Serial serial) {
ASSERT(values.size() > 0);
ASSERT(Empty() || storage.back().first <= serial);
storage.emplace_back(SerialPair(serial, {values}));
return *this;
}
template<typename T>
bool SerialQueue<T>::Iterator::operator==(const typename SerialQueue<T>::Iterator& other) const {
return other.storageIterator == storageIterator && other.serialIterator == serialIterator;
}
template<typename T>
bool SerialQueue<T>::Iterator::operator!=(const typename SerialQueue<T>::Iterator& other) const {
return !(*this == other);
}
template<typename T>
T& SerialQueue<T>::Iterator::operator*() const {
if (serialIterator == nullptr) {
return *storageIterator->second.begin();
}
return *serialIterator;
}
// SerialQueue::ConstBeginEnd
template<typename T>
SerialQueue<T>::ConstBeginEnd::ConstBeginEnd(typename SerialQueue<T>::ConstStorageIterator start, typename SerialQueue<T>::ConstStorageIterator end)
: startIt(start), endIt(end) {
}
template<typename T>
typename SerialQueue<T>::ConstIterator SerialQueue<T>::ConstBeginEnd::begin() const {
return {startIt};
}
template<typename T>
typename SerialQueue<T>::ConstIterator SerialQueue<T>::ConstBeginEnd::end() const {
return {endIt};
}
// SerialQueue::ConstIterator
template<typename T>
SerialQueue<T>::ConstIterator::ConstIterator(typename SerialQueue<T>::ConstStorageIterator start)
: storageIterator(start), serialIterator(nullptr) {
}
template<typename T>
typename SerialQueue<T>::ConstIterator& SerialQueue<T>::ConstIterator::operator++() {
const T* vectorData = storageIterator->second.data();
if (serialIterator == nullptr) {
serialIterator = vectorData + 1;
} else {
serialIterator ++;
}
template<typename T>
void SerialQueue<T>::Enqueue(std::vector<T>&& values, Serial serial) {
ASSERT(values.size() > 0);
ASSERT(Empty() || storage.back().first <= serial);
storage.emplace_back(SerialPair(serial, {values}));
if (serialIterator >= vectorData + storageIterator->second.size()) {
serialIterator = nullptr;
storageIterator ++;
}
template<typename T>
bool SerialQueue<T>::Empty() const {
return storage.empty();
}
template<typename T>
typename SerialQueue<T>::ConstBeginEnd SerialQueue<T>::IterateAll() const {
return {storage.begin(), storage.end()};
}
template<typename T>
typename SerialQueue<T>::ConstBeginEnd SerialQueue<T>::IterateUpTo(Serial serial) const {
return {storage.begin(), FindUpTo(serial)};
}
template<typename T>
typename SerialQueue<T>::BeginEnd SerialQueue<T>::IterateAll() {
return {storage.begin(), storage.end()};
}
template<typename T>
typename SerialQueue<T>::BeginEnd SerialQueue<T>::IterateUpTo(Serial serial) {
return {storage.begin(), FindUpTo(serial)};
}
template<typename T>
void SerialQueue<T>::Clear() {
storage.clear();
}
template<typename T>
void SerialQueue<T>::ClearUpTo(Serial serial) {
storage.erase(storage.begin(), FindUpTo(serial));
}
template<typename T>
Serial SerialQueue<T>::FirstSerial() const {
ASSERT(!Empty());
return storage.front().first;
}
template<typename T>
typename SerialQueue<T>::ConstStorageIterator SerialQueue<T>::FindUpTo(Serial serial) const {
auto it = storage.begin();
while (it != storage.end() && it->first <= serial) {
it ++;
}
return it;
}
template<typename T>
typename SerialQueue<T>::StorageIterator SerialQueue<T>::FindUpTo(Serial serial) {
auto it = storage.begin();
while (it != storage.end() && it->first <= serial) {
it ++;
}
return it;
}
// SerialQueue::BeginEnd
template<typename T>
SerialQueue<T>::BeginEnd::BeginEnd(typename SerialQueue<T>::StorageIterator start, typename SerialQueue<T>::StorageIterator end)
: startIt(start), endIt(end) {
}
template<typename T>
typename SerialQueue<T>::Iterator SerialQueue<T>::BeginEnd::begin() const {
return {startIt};
}
template<typename T>
typename SerialQueue<T>::Iterator SerialQueue<T>::BeginEnd::end() const {
return {endIt};
}
// SerialQueue::Iterator
template<typename T>
SerialQueue<T>::Iterator::Iterator(typename SerialQueue<T>::StorageIterator start)
: storageIterator(start), serialIterator(nullptr) {
}
template<typename T>
typename SerialQueue<T>::Iterator& SerialQueue<T>::Iterator::operator++() {
T* vectorData = storageIterator->second.data();
if (serialIterator == nullptr) {
serialIterator = vectorData + 1;
} else {
serialIterator ++;
}
if (serialIterator >= vectorData + storageIterator->second.size()) {
serialIterator = nullptr;
storageIterator ++;
}
return *this;
}
template<typename T>
bool SerialQueue<T>::Iterator::operator==(const typename SerialQueue<T>::Iterator& other) const {
return other.storageIterator == storageIterator && other.serialIterator == serialIterator;
}
template<typename T>
bool SerialQueue<T>::Iterator::operator!=(const typename SerialQueue<T>::Iterator& other) const {
return !(*this == other);
}
template<typename T>
T& SerialQueue<T>::Iterator::operator*() const {
if (serialIterator == nullptr) {
return *storageIterator->second.begin();
}
return *serialIterator;
}
// SerialQueue::ConstBeginEnd
template<typename T>
SerialQueue<T>::ConstBeginEnd::ConstBeginEnd(typename SerialQueue<T>::ConstStorageIterator start, typename SerialQueue<T>::ConstStorageIterator end)
: startIt(start), endIt(end) {
}
template<typename T>
typename SerialQueue<T>::ConstIterator SerialQueue<T>::ConstBeginEnd::begin() const {
return {startIt};
}
template<typename T>
typename SerialQueue<T>::ConstIterator SerialQueue<T>::ConstBeginEnd::end() const {
return {endIt};
}
// SerialQueue::ConstIterator
template<typename T>
SerialQueue<T>::ConstIterator::ConstIterator(typename SerialQueue<T>::ConstStorageIterator start)
: storageIterator(start), serialIterator(nullptr) {
}
template<typename T>
typename SerialQueue<T>::ConstIterator& SerialQueue<T>::ConstIterator::operator++() {
const T* vectorData = storageIterator->second.data();
if (serialIterator == nullptr) {
serialIterator = vectorData + 1;
} else {
serialIterator ++;
}
if (serialIterator >= vectorData + storageIterator->second.size()) {
serialIterator = nullptr;
storageIterator ++;
}
return *this;
}
template<typename T>
bool SerialQueue<T>::ConstIterator::operator==(const typename SerialQueue<T>::ConstIterator& other) const {
return other.storageIterator == storageIterator && other.serialIterator == serialIterator;
}
template<typename T>
bool SerialQueue<T>::ConstIterator::operator!=(const typename SerialQueue<T>::ConstIterator& other) const {
return !(*this == other);
}
template<typename T>
const T& SerialQueue<T>::ConstIterator::operator*() const {
if (serialIterator == nullptr) {
return *storageIterator->second.begin();
}
return *serialIterator;
return *this;
}
template<typename T>
bool SerialQueue<T>::ConstIterator::operator==(const typename SerialQueue<T>::ConstIterator& other) const {
return other.storageIterator == storageIterator && other.serialIterator == serialIterator;
}
template<typename T>
bool SerialQueue<T>::ConstIterator::operator!=(const typename SerialQueue<T>::ConstIterator& other) const {
return !(*this == other);
}
template<typename T>
const T& SerialQueue<T>::ConstIterator::operator*() const {
if (serialIterator == nullptr) {
return *storageIterator->second.begin();
}
return *serialIterator;
}
#endif // COMMON_SERIALQUEUE_H_