// DescriptionHere - common.h
// Created by John Ryland (jryland@xiaofrog.com), 02/11/2017
// Copyright (c) 2017 InvertedLogic
// All rights reserved.
#pragma once
// Mainly this is just designed for using with std::vector with pre C++11 compilers
#define foreach(item, vec) \
for (size_t keep = 1, count = 0, size = vec.size(); keep && count != size; keep = !keep, count++) \
for (item = vec[count]; keep; keep = !keep)
/*
Opaque Object Pattern - how to do without pointers?
-- header ------
#pragma once
struct SomeClass; // forward declaration
bool SomeClass_Init(SomeClass&); // constructor - but doesn't allocate
void SomeClass_Deinit(SomeClass&); // destructor
void SomeClass_SomeFunc(SomeClass&, int args);
// ... other functions
----------------
Problem here, there isn't a way given to allocate an object, just construct/init.
If know the size then can allocate on the heap, but not on the stack.
Only way to allocate on the stack is to know the size at compile time.
Knowing the size at compile time implies either making non-opaque, or having to
do something messy to keep some const size variable in sync with the struct definition.
----------------
Perhaps the solution is to automate this as a build step? It's an extra build pass, but
there might be compiling speed ups though from using opaque objects instead.
There might be a dependancy issue though in that the size of an object which contains
another object first needs the size of the other object to work out its own size. The
extra build pass that does this would need to figure that out.
----------------
alternative c++ approach is pimpl way, but this turns everything in to pointers
and extra allocations etc. No good for tiny objects in the 1000s. Fine for small numbers
of big objects where it makes sense.
----------------
Functional ADTs:
https://en.wikipedia.org/wiki/Abstract_data_type
functional programming style ADTs can be achieved by returning the new state
struct Stack;
typedef Stack* StackRef; // type: handle to a stack state (opaque pointer)
typedef void* StackItem; // type: value of a stack state (arbitrary address)
StackRef Stack_Empty();
StackRef Stack_Push(StackRef s, StackItem x);
StackRef Stack_Pop(StackRef s);
StackItem Stack_Top(StackRef s);
Can chain calls together:
StackItem item = Stack_Top(Stack_Push(Stack_Push(Stack_Empty(), StackItem_Int(10)), StackItem_Int(20)));
// Word stack appears alot above, perhaps c++ can automate something here
struct StackCls // equivolent in size to a StackRef
{
static StackCls Empty() { return (StackCls){Stack_Empty()}; }
StackCls Push(StackItem x) { return (StackCls){Stack_Push(m_stack, x)}; }
StackCls Pop() { return (StackCls){Stack_Pop(m_stack)}; }
StackItem Top() { return Stack_Top(m_stack); }
private:
StackRef m_stack;
};
How much different is this compared with using pimpl?
Can chain calls together like this instead:
StackItem item = StackCls::Empty().Push(StackItem_Int(10)).Push(StackItem_Int(20)).Top();
// It is a bit less wordy and perhaps reads a bit better
// I'm not sure if the overhead is zero or not, it may depend on the compiler, but it is small
*/