+bool ParanoidNumber::SanityCheck(set<ParanoidNumber*> & visited) const
+{
+ if (this == NULL)
+ {
+ Error("NULL pointer in tree");
+ return false;
+ }
+
+ if (visited.find((ParanoidNumber*)this) != visited.end())
+ {
+ Error("I think I've seen this tree before...");
+ return false;
+ }
+
+ visited.insert((ParanoidNumber*)this);
+
+ for (auto add : m_next[ADD])
+ {
+ if (!add->SanityCheck(visited))
+ return false;
+ }
+ for (auto sub : m_next[SUBTRACT])
+ {
+ if (!sub->SanityCheck(visited))
+ return false;
+ }
+ for (auto mul : m_next[MULTIPLY])
+ {
+ if (!mul->SanityCheck(visited))
+ return false;
+ }
+
+ for (auto div : m_next[DIVIDE])
+ {
+ if (!div->SanityCheck(visited))
+ return false;
+ if (div->Digit() == 0)
+ {
+ Error("Divide by zero");
+ return false;
+ }
+ }
+ return true;
+}
+
+void ParanoidNumber::Negate()
+{
+ swap(m_next[ADD], m_next[SUBTRACT]);
+ m_value = -m_value;
+ #ifdef PARANOID_CACHE_RESULTS
+ m_cached_result = -m_cached_result;
+ #endif
+}
+
+#ifdef PARANOID_USE_ARENA
+
+void * ParanoidNumber::operator new(size_t s)
+{
+ return g_arena.allocate(s);
+}
+
+void ParanoidNumber::operator delete(void * p)
+{
+ g_arena.deallocate(p);
+}
+
+ParanoidNumber::Arena::Arena(int64_t block_size) : m_block_size(block_size), m_spare(NULL)
+{
+ m_blocks.push_back({malloc(block_size*sizeof(ParanoidNumber)),0});
+}
+
+ParanoidNumber::Arena::~Arena()
+{
+ for (auto block : m_blocks)
+ {
+ free(block.memory);
+ }
+ m_blocks.clear();
+}
+
+void * ParanoidNumber::Arena::allocate(size_t s)
+{
+ if (m_spare != NULL)
+ {
+ void * result = m_spare;
+ m_spare = NULL;
+ return result;
+ }
+
+ Block & b = m_blocks.back();
+ void * result = (ParanoidNumber*)(b.memory) + (b.used++);
+ if (b.used >= m_block_size)
+ {
+ m_block_size *= 2;
+ Debug("Add block of size %d", m_block_size);
+ m_blocks.push_back({malloc(m_block_size*sizeof(ParanoidNumber)), 0});
+ }
+ return result;
+}
+
+void ParanoidNumber::Arena::deallocate(void * p)
+{
+ m_spare = p;
+}
+#endif //PARANOID_USE_ARENA