--- a +++ b/functions/@mmo/mmo.m @@ -0,0 +1,165 @@ +% MMO - create a memory-mapped data class +% +% Usage: +% >> data_class = mmo(data); +% +% Inputs: +% data - input data or data file +% +% Outputs: +% data_class - output dataset class +% +% Author: Arnaud Delorme, SCCN, INC, UCSD, Nov. 2012- + +% Copyright (C) 2008 Arnaud Delorme, SCCN, INC, UCSD +% +% This file is part of EEGLAB, see http://www.eeglab.org +% for the documentation and details. +% +% Redistribution and use in source and binary forms, with or without +% modification, are permitted provided that the following conditions are met: +% +% 1. Redistributions of source code must retain the above copyright notice, +% this list of conditions and the following disclaimer. +% +% 2. Redistributions in binary form must reproduce the above copyright notice, +% this list of conditions and the following disclaimer in the documentation +% and/or other materials provided with the distribution. +% +% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +% THE POSSIBILITY OF SUCH DAMAGE. + +classdef mmo + properties + dataFile = []; + dimensions = []; + writable = true; % duplicate of the writable field of memmapfile + workspace = []; + type = 'mmo'; + transposed = false; + debug = false; + end + + methods + function dataout = mmo(dataFileIn, datadims, writableVal, transposedVal, debugVal) + if nargin < 3 + writableVal = true; + end + if nargin < 4 + transposedVal = false; + end + if nargin < 5 + debugVal = false; + end + + % check that the file is not empty + % -------------------------------- + if ~isempty(dataFileIn) + if ~ischar(dataFileIn) + error('First input must be a file name'); + end + + dirContent = dir(dataFileIn); + if isempty(dirContent) + error([ 'Data file ''' dataFileIn '''not found' ]); + elseif dirContent(1).bytes == 0 + error([ 'Empty data file ''' dataFileIn '''' ]); + end + else + dataFileIn = mmo.getnewfilename; + fid = fopen(dataFileIn, 'w'); + if fid == -1, error('Cannot open new file'); end + if length(datadims) == 1, datadims(2) = 1; end + tmpdata = zeros(1, prod(datadims(2:end)), 'single'); + for index = 1:datadims(1) + fwrite(fid, tmpdata, 'float'); + end + fclose(fid); + end + + % test memory map but discards it + % ------------------------------- + test = memmapfile(dataFileIn, 'writable', writableVal, 'format', { 'single' datadims 'x' }); + clear test; + + % set fields + % ---------- + while datadims(end) == 1 && length(datadims) > 1 + datadims(end) = []; + end + if transposedVal + if length(datadims) == 1, datadims = [1 datadims]; + else datadims = [datadims(2:end) datadims(1)]; + end + end + + dataout.dataFile = dataFileIn; + dataout.dimensions = datadims; + dataout.writable = writableVal; + dataout.transposed = transposedVal; + + % set workspace + % ------------- + dataout = updateWorkspace(dataout); +% stack = dbstack; +% stack(1) = []; +% stack = rmfield(stack, 'line'); +% dataout.workspace = stack; + dataout.debug = debugVal; + end + + % this function updates the function workspace + % -------------------------------------------- + function obj = updateWorkspace(obj); + stack = dbstack; + stack(1:2) = []; + stack = rmfield(stack, 'line'); + obj.workspace = stack; + end + + % function to check copies (only used for testing, + % implemented in subasign as well) + % -------------------------------- + function ncopies = checkcopies(obj); + ncopies = checkworkspace(obj); + if ncopies < 2 + s = evalin('caller', 'whos'); + for index = 1:length(s) + if strcmpi(s(index).class, 'struct') || strcmpi(s(index).class, 'cell') + tmpVar = evalin('caller', s(index).name); + ncopies = ncopies + checkcopies_local(obj, tmpVar); + elseif strcmpi(s(index).class, 'mmo') + if s(index).persistent || s(index).global + disp('Warning: mmo objects should not be made persistent or global. Behavior is unpredictable.'); + end + tmpVar = evalin('caller', s(index).name); + if isequal(tmpVar, obj), ncopies = ncopies + 1; end + if ncopies > 1, break; end + end + end + end + end + + % numerical implementations of basic functions + % -------------------------------------------- + function obj2 = log(obj1); obj2 = unitaryopp(@log, obj1); end + function val = mean(obj,dim); if nargin <1, dim=1; end; val = sum(obj,dim)/size(obj,dim); end + function val = std(varargin); val = sqrt(var(varargin{:})); end + function obj3 = minus(obj1, obj2); obj3 = binaryopp(@minus, obj1, obj2); end + function obj3 = plus(obj1, obj2); obj3 = binaryopp(@plus, obj1, obj2); end + function obj3 = time(obj1, obj2); obj3 = binaryopp(@time, obj1, obj2); end + end + + methods (Static) + function str = getnewfilename; str = fullfile(gettempfolder(true), sprintf('memapdata_%.9d%.9d.fdt', round(rand(1)*10^9), round(rand(1)*10^9))); end + end +end