a b/functions/@mmo/mmo.m
1
% MMO - create a memory-mapped data class
2
%
3
% Usage:
4
%   >> data_class = mmo(data);
5
%
6
% Inputs:
7
%   data         - input data or data file
8
%
9
% Outputs:
10
%   data_class    - output dataset class
11
%
12
% Author: Arnaud Delorme, SCCN, INC, UCSD, Nov. 2012-
13
14
% Copyright (C) 2008 Arnaud Delorme, SCCN, INC, UCSD
15
%
16
% This file is part of EEGLAB, see http://www.eeglab.org
17
% for the documentation and details.
18
%
19
% Redistribution and use in source and binary forms, with or without
20
% modification, are permitted provided that the following conditions are met:
21
%
22
% 1. Redistributions of source code must retain the above copyright notice,
23
% this list of conditions and the following disclaimer.
24
%
25
% 2. Redistributions in binary form must reproduce the above copyright notice,
26
% this list of conditions and the following disclaimer in the documentation
27
% and/or other materials provided with the distribution.
28
%
29
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
30
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
33
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
39
% THE POSSIBILITY OF SUCH DAMAGE.
40
41
classdef mmo
42
    properties
43
        dataFile   = [];
44
        dimensions = [];
45
        writable   = true;  % duplicate of the writable field of memmapfile
46
        workspace  = [];
47
        type       = 'mmo';
48
        transposed = false;
49
        debug      = false;
50
    end
51
        
52
    methods
53
        function dataout = mmo(dataFileIn, datadims, writableVal, transposedVal, debugVal)
54
            if nargin < 3
55
                writableVal = true;
56
            end
57
            if nargin < 4
58
                transposedVal = false;
59
            end
60
            if nargin < 5
61
                debugVal = false;
62
            end
63
            
64
            % check that the file is not empty
65
            % --------------------------------
66
            if ~isempty(dataFileIn)
67
                if ~ischar(dataFileIn)
68
                    error('First input must be a file name');
69
                end
70
71
                dirContent = dir(dataFileIn);
72
                if isempty(dirContent)
73
                    error([ 'Data file ''' dataFileIn '''not found' ]);
74
                elseif dirContent(1).bytes == 0
75
                    error([ 'Empty data file ''' dataFileIn '''' ]);
76
                end
77
            else
78
                dataFileIn = mmo.getnewfilename;
79
                fid = fopen(dataFileIn, 'w');
80
                if fid == -1, error('Cannot open new file'); end
81
                if length(datadims) == 1, datadims(2) = 1; end
82
                tmpdata = zeros(1, prod(datadims(2:end)), 'single');
83
                for index = 1:datadims(1)
84
                    fwrite(fid, tmpdata, 'float');
85
                end
86
                fclose(fid);
87
            end
88
                
89
            % test memory map but discards it
90
            % -------------------------------
91
            test = memmapfile(dataFileIn, 'writable', writableVal, 'format', { 'single' datadims 'x' });
92
            clear test;
93
            
94
            % set fields
95
            % ----------
96
            while datadims(end) == 1 && length(datadims) > 1
97
                datadims(end) = [];
98
            end
99
            if transposedVal
100
                if length(datadims) == 1, datadims = [1 datadims];
101
                else                      datadims = [datadims(2:end) datadims(1)];
102
                end
103
            end
104
            
105
            dataout.dataFile   = dataFileIn;
106
            dataout.dimensions = datadims;
107
            dataout.writable   = writableVal;
108
            dataout.transposed = transposedVal;
109
            
110
            % set workspace
111
            % -------------
112
            dataout = updateWorkspace(dataout);
113
%             stack = dbstack;
114
%             stack(1) = [];
115
%             stack = rmfield(stack, 'line');
116
%             dataout.workspace = stack;
117
            dataout.debug     = debugVal;
118
        end
119
        
120
        % this function updates the function workspace
121
        % --------------------------------------------
122
        function obj = updateWorkspace(obj);
123
            stack = dbstack;
124
            stack(1:2) = [];
125
            stack      = rmfield(stack, 'line');
126
            obj.workspace = stack;
127
        end
128
        
129
        % function to check copies (only used for testing,
130
        % implemented in subasign as well)
131
        % --------------------------------
132
        function ncopies = checkcopies(obj);
133
            ncopies = checkworkspace(obj);
134
            if ncopies < 2
135
                s = evalin('caller', 'whos');
136
                for index = 1:length(s)
137
                    if strcmpi(s(index).class, 'struct') || strcmpi(s(index).class, 'cell')
138
                        tmpVar = evalin('caller', s(index).name);
139
                        ncopies = ncopies + checkcopies_local(obj, tmpVar);
140
                    elseif strcmpi(s(index).class, 'mmo')
141
                        if s(index).persistent || s(index).global
142
                            disp('Warning: mmo objects should not be made persistent or global. Behavior is unpredictable.');
143
                        end
144
                        tmpVar = evalin('caller', s(index).name);
145
                        if isequal(tmpVar, obj), ncopies = ncopies + 1; end
146
                        if ncopies > 1, break; end
147
                    end
148
                end
149
            end
150
        end
151
        
152
        % numerical implementations of basic functions
153
        % --------------------------------------------
154
        function obj2 = log(obj1); obj2 = unitaryopp(@log, obj1); end
155
        function val  = mean(obj,dim); if nargin <1, dim=1; end; val = sum(obj,dim)/size(obj,dim); end
156
        function val  = std(varargin); val = sqrt(var(varargin{:})); end
157
        function obj3 = minus(obj1, obj2); obj3 = binaryopp(@minus, obj1, obj2); end
158
        function obj3 = plus(obj1, obj2); obj3 = binaryopp(@plus, obj1, obj2); end
159
        function obj3 = time(obj1, obj2); obj3 = binaryopp(@time, obj1, obj2); end
160
    end
161
    
162
    methods (Static)
163
        function str  = getnewfilename; str = fullfile(gettempfolder(true), sprintf('memapdata_%.9d%.9d.fdt', round(rand(1)*10^9), round(rand(1)*10^9))); end
164
    end
165
end