function varargout=mmgr(action,varargin)
% ptr/mmgr: memory manager for pointer objects (for internal use only)
% usage: [...] = mmgr(action,...)
% x = mmgr(1,ind)
% mmgr(2,ind,x)
% ind = mmgr(3)
% ind = mmgr(3,x)
% mmgr(4,ind)
% x = mmgr(4,ind)
% mmgr(0)
%
% action is an integer specifying what is to be done in memory:
% 1: mread - read the memory at ind
% 2: mwrite - assign ind to memory at x
% 3: malloc - allocate memory (optionally initialize to x)
% 4: mfree - deallocate memory at ind (optionally returning value)
% 0: mwipe - deallocate all memory
%
% No error checking is done here.
%
% See also: mread, mwrite, malloc, mfree
% Author: Ben Petschel 31/8/2009
% Version History:
% 31/8/2009 - initial release
% mem is a cell array representing memory
% memused is a boolean array with value true if mem{i} is used
% memnext is an index into the first unused position in mem
persistent mem memused memnext
if isempty(mem)
mem=cell(1);
memused=false;
memnext=1;
end;
switch action
case 1
% mread: x = mmgr(1,ind)
%ind=varargin{1};x=mem{ind};varargout{1}=x;
ind = varargin{1};
if ind<=numel(mem)
varargout{1} = mem{ind};
else
% reading non-assigned memory, so return hexadecimal gibberish
varargout{1} = num2hex(single(exp(10*randn)*randn(ceil(10*rand),1)));
end;
case 2
% mwrite: mmgr(2,ind,x)
%ind=varargin{1};x= varargin{2};mem{ind}=x;
ind = varargin{1};
if ind<=numel(mem)
mem{ind}=varargin{2};
else
dumpcore=true; % change this to false to avoid saving core
if dumpcore
save core mem memused memnext ind
end;
error('ptr:mmgr:mwrite','segmentation fault (core dumped)');
end;
case 3
% malloc: ind = mmgr(3) or ind = mmgr(3,x)
% allocate mem
ind = memnext;
nmem = numel(mem);
if ind > nmem
% double size of mem (potentially wasteful but much faster than
% appending elements one by one!)
mem = [mem,cell(1,nmem)];
memused = [memused,false(1,nmem)];
end;
% place x in mem
if nargin==2
mem{ind}=varargin{1};
% otherwise mem is already []
end;
memused(ind)=true;
% find the next free memory index
memnext = ind+1;
while (memnext <= nmem) && memused(memnext)
memnext = memnext+1;
end;
varargout{1}=ind;
case 4
% mfree: mmgr(4,ind) or x = mmgr(4,ind)
ind=varargin{1};
if nargout==1
varargout{1}=mem{ind};
end;
mem{ind} = [];
memused(ind) = false;
memnext = min(memnext,ind);
case 0
% wipe memory
mem=cell(1);
memused=false;
memnext=1;
otherwise
error('ptr:mmgr:action','action not recognized');
end;