aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Doxyfile1608
-rw-r--r--src/experimental/debugmutex.cpp78
-rw-r--r--src/experimental/debugmutex.h102
-rw-r--r--src/stable/file.cpp22
-rw-r--r--src/stable/mutex.h8
-rw-r--r--src/stable/myriad.cpp1226
-rw-r--r--src/stable/myriad.h347
-rw-r--r--src/stable/myriadstream.cpp284
-rw-r--r--src/stable/myriadstream.h46
-rw-r--r--src/tests/bigmyriad.cpp15
-rw-r--r--src/tests/cachedel.cpp27
-rw-r--r--src/tests/myriad.cpp23
-rw-r--r--src/tests/myriadfs.cpp2
-rw-r--r--src/tools/myriad.cpp97
-rw-r--r--src/unit/myriad.unit46
-rw-r--r--src/unstable/bitstring.cpp12
-rw-r--r--src/unstable/bitstring.h10
-rw-r--r--src/unstable/cachebase.h10
-rw-r--r--src/unstable/myriadcache.h28
-rw-r--r--src/unstable/myriadfs.cpp76
-rw-r--r--src/unstable/myriadfs.h14
21 files changed, 1444 insertions, 2637 deletions
diff --git a/Doxyfile b/Doxyfile
index 23de8ba..33a33f6 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -1,105 +1,20 @@
1# Doxyfile 1.8.1 1# Doxyfile 1.9.4
2
3# This file describes the settings to be used by the documentation system
4# doxygen (www.doxygen.org) for a project.
5#
6# All text after a hash (#) is considered a comment and will be ignored.
7# The format is:
8# TAG = value [value, ...]
9# For lists items can also be appended using:
10# TAG += value [value, ...]
11# Values that contain spaces should be placed between quotes (" ").
12 2
13#--------------------------------------------------------------------------- 3#---------------------------------------------------------------------------
14# Project related configuration options 4# Project related configuration options
15#--------------------------------------------------------------------------- 5#---------------------------------------------------------------------------
16
17# This tag specifies the encoding used for all characters in the config file
18# that follow. The default is UTF-8 which is also the encoding used for all
19# text before the first occurrence of this tag. Doxygen uses libiconv (or the
20# iconv built into libc) for the transcoding. See
21# http://www.gnu.org/software/libiconv for the list of possible encodings.
22
23DOXYFILE_ENCODING = UTF-8 6DOXYFILE_ENCODING = UTF-8
24
25# The PROJECT_NAME tag is a single word (or sequence of words) that should
26# identify the project. Note that if you do not use Doxywizard you need
27# to put quotes around the project name if it contains spaces.
28
29PROJECT_NAME = libbu++ 7PROJECT_NAME = libbu++
30
31# The PROJECT_NUMBER tag can be used to enter a project or revision number.
32# This could be handy for archiving the generated documentation or
33# if some version control system is used.
34
35PROJECT_NUMBER = $VERSION$ 8PROJECT_NUMBER = $VERSION$
36
37# Using the PROJECT_BRIEF tag one can provide an optional one line description
38# for a project that appears at the top of each page and should give viewer
39# a quick idea about the purpose of the project. Keep the description short.
40
41PROJECT_BRIEF = 9PROJECT_BRIEF =
42
43# With the PROJECT_LOGO tag one can specify an logo or icon that is
44# included in the documentation. The maximum height of the logo should not
45# exceed 55 pixels and the maximum width should not exceed 200 pixels.
46# Doxygen will copy the logo to the output directory.
47
48PROJECT_LOGO = 10PROJECT_LOGO =
49
50# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
51# base path where the generated documentation will be put.
52# If a relative path is entered, it will be relative to the location
53# where doxygen was started. If left blank the current directory will be used.
54
55OUTPUT_DIRECTORY = api 11OUTPUT_DIRECTORY = api
56
57# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
58# 4096 sub-directories (in 2 levels) under the output directory of each output
59# format and will distribute the generated files over these directories.
60# Enabling this option can be useful when feeding doxygen a huge amount of
61# source files, where putting all generated files in the same directory would
62# otherwise cause performance problems for the file system.
63
64CREATE_SUBDIRS = NO 12CREATE_SUBDIRS = NO
65 13CREATE_SUBDIRS_LEVEL = 8
66# The OUTPUT_LANGUAGE tag is used to specify the language in which all 14ALLOW_UNICODE_NAMES = NO
67# documentation generated by doxygen is written. Doxygen will use this
68# information to generate all constant output in the proper language.
69# The default language is English, other supported languages are:
70# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
71# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
72# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
73# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
74# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
75# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
76
77OUTPUT_LANGUAGE = English 15OUTPUT_LANGUAGE = English
78
79# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
80# include brief member descriptions after the members that are listed in
81# the file and class documentation (similar to JavaDoc).
82# Set to NO to disable this.
83
84BRIEF_MEMBER_DESC = YES 16BRIEF_MEMBER_DESC = YES
85
86# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
87# the brief description of a member or function before the detailed description.
88# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
89# brief descriptions will be completely suppressed.
90
91REPEAT_BRIEF = YES 17REPEAT_BRIEF = YES
92
93# This tag implements a quasi-intelligent brief description abbreviator
94# that is used to form the text in various listings. Each string
95# in this list, if found as the leading text of the brief description, will be
96# stripped from the text and the result after processing the whole list, is
97# used as the annotated text. Otherwise, the brief description is used as-is.
98# If left blank, the following values are used ("$name" is automatically
99# replaced with the name of the entity): "The $name class" "The $name widget"
100# "The $name file" "is" "provides" "specifies" "contains"
101# "represents" "a" "an" "the"
102
103ABBREVIATE_BRIEF = "The $name class" \ 18ABBREVIATE_BRIEF = "The $name class" \
104 "The $name widget" \ 19 "The $name widget" \
105 "The $name file" \ 20 "The $name file" \
@@ -111,582 +26,107 @@ ABBREVIATE_BRIEF = "The $name class" \
111 a \ 26 a \
112 an \ 27 an \
113 the 28 the
114
115# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
116# Doxygen will generate a detailed section even if there is only a brief
117# description.
118
119ALWAYS_DETAILED_SEC = NO 29ALWAYS_DETAILED_SEC = NO
120
121# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
122# inherited members of a class in the documentation of that class as if those
123# members were ordinary class members. Constructors, destructors and assignment
124# operators of the base classes will not be shown.
125
126INLINE_INHERITED_MEMB = NO 30INLINE_INHERITED_MEMB = NO
127
128# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
129# path before files name in the file list and in the header files. If set
130# to NO the shortest path that makes the file name unique will be used.
131
132FULL_PATH_NAMES = NO 31FULL_PATH_NAMES = NO
133
134# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
135# can be used to strip a user-defined part of the path. Stripping is
136# only done if one of the specified strings matches the left-hand part of
137# the path. The tag can be used to show relative paths in the file list.
138# If left blank the directory from which doxygen is run is used as the
139# path to strip.
140
141STRIP_FROM_PATH = 32STRIP_FROM_PATH =
142
143# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
144# the path mentioned in the documentation of a class, which tells
145# the reader which header file to include in order to use a class.
146# If left blank only the name of the header file containing the class
147# definition is used. Otherwise one should specify the include paths that
148# are normally passed to the compiler using the -I flag.
149
150STRIP_FROM_INC_PATH = 33STRIP_FROM_INC_PATH =
151
152# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
153# (but less readable) file names. This can be useful if your file system
154# doesn't support long names like on DOS, Mac, or CD-ROM.
155
156SHORT_NAMES = NO 34SHORT_NAMES = NO
157
158# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
159# will interpret the first line (until the first dot) of a JavaDoc-style
160# comment as the brief description. If set to NO, the JavaDoc
161# comments will behave just like regular Qt-style comments
162# (thus requiring an explicit @brief command for a brief description.)
163
164JAVADOC_AUTOBRIEF = YES 35JAVADOC_AUTOBRIEF = YES
165 36JAVADOC_BANNER = NO
166# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
167# interpret the first line (until the first dot) of a Qt-style
168# comment as the brief description. If set to NO, the comments
169# will behave just like regular Qt-style comments (thus requiring
170# an explicit \brief command for a brief description.)
171
172QT_AUTOBRIEF = NO 37QT_AUTOBRIEF = NO
173
174# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
175# treat a multi-line C++ special comment block (i.e. a block of //! or ///
176# comments) as a brief description. This used to be the default behaviour.
177# The new default is to treat a multi-line C++ comment block as a detailed
178# description. Set this tag to YES if you prefer the old behaviour instead.
179
180MULTILINE_CPP_IS_BRIEF = NO 38MULTILINE_CPP_IS_BRIEF = NO
181 39PYTHON_DOCSTRING = YES
182# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
183# member inherits the documentation from any documented member that it
184# re-implements.
185
186INHERIT_DOCS = YES 40INHERIT_DOCS = YES
187
188# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
189# a new page for each member. If set to NO, the documentation of a member will
190# be part of the file/class/namespace that contains it.
191
192SEPARATE_MEMBER_PAGES = NO 41SEPARATE_MEMBER_PAGES = NO
193
194# The TAB_SIZE tag can be used to set the number of spaces in a tab.
195# Doxygen uses this value to replace tabs by spaces in code fragments.
196
197TAB_SIZE = 4 42TAB_SIZE = 4
198
199# This tag can be used to specify a number of aliases that acts
200# as commands in the documentation. An alias has the form "name=value".
201# For example adding "sideeffect=\par Side Effects:\n" will allow you to
202# put the command \sideeffect (or @sideeffect) in the documentation, which
203# will result in a user-defined paragraph with heading "Side Effects:".
204# You can put \n's in the value part of an alias to insert newlines.
205
206ALIASES = 43ALIASES =
207
208# This tag can be used to specify a number of word-keyword mappings (TCL only).
209# A mapping has the form "name=value". For example adding
210# "class=itcl::class" will allow you to use the command class in the
211# itcl::class meaning.
212
213TCL_SUBST =
214
215# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
216# sources only. Doxygen will then generate output that is more tailored for C.
217# For instance, some of the names that are used will be different. The list
218# of all members will be omitted, etc.
219
220OPTIMIZE_OUTPUT_FOR_C = NO 44OPTIMIZE_OUTPUT_FOR_C = NO
221
222# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
223# sources only. Doxygen will then generate output that is more tailored for
224# Java. For instance, namespaces will be presented as packages, qualified
225# scopes will look different, etc.
226
227OPTIMIZE_OUTPUT_JAVA = NO 45OPTIMIZE_OUTPUT_JAVA = NO
228
229# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
230# sources only. Doxygen will then generate output that is more tailored for
231# Fortran.
232
233OPTIMIZE_FOR_FORTRAN = NO 46OPTIMIZE_FOR_FORTRAN = NO
234
235# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
236# sources. Doxygen will then generate output that is tailored for
237# VHDL.
238
239OPTIMIZE_OUTPUT_VHDL = NO 47OPTIMIZE_OUTPUT_VHDL = NO
240 48OPTIMIZE_OUTPUT_SLICE = NO
241# Doxygen selects the parser to use depending on the extension of the files it
242# parses. With this tag you can assign which parser to use for a given extension.
243# Doxygen has a built-in mapping, but you can override or extend it using this
244# tag. The format is ext=language, where ext is a file extension, and language
245# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
246# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
247# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
248# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
249# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
250
251EXTENSION_MAPPING = 49EXTENSION_MAPPING =
252
253# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
254# comments according to the Markdown format, which allows for more readable
255# documentation. See http://daringfireball.net/projects/markdown/ for details.
256# The output of markdown processing is further processed by doxygen, so you
257# can mix doxygen, HTML, and XML commands with Markdown formatting.
258# Disable only in case of backward compatibilities issues.
259
260MARKDOWN_SUPPORT = YES 50MARKDOWN_SUPPORT = YES
261 51TOC_INCLUDE_HEADINGS = 5
262# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 52AUTOLINK_SUPPORT = YES
263# to include (a tag file for) the STL sources as input, then you should
264# set this tag to YES in order to let doxygen match functions declarations and
265# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
266# func(std::string) {}). This also makes the inheritance and collaboration
267# diagrams that involve STL classes more complete and accurate.
268
269BUILTIN_STL_SUPPORT = NO 53BUILTIN_STL_SUPPORT = NO
270
271# If you use Microsoft's C++/CLI language, you should set this option to YES to
272# enable parsing support.
273
274CPP_CLI_SUPPORT = NO 54CPP_CLI_SUPPORT = NO
275
276# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
277# Doxygen will parse them like normal C++ but will assume all classes use public
278# instead of private inheritance when no explicit protection keyword is present.
279
280SIP_SUPPORT = NO 55SIP_SUPPORT = NO
281
282# For Microsoft's IDL there are propget and propput attributes to indicate getter
283# and setter methods for a property. Setting this option to YES (the default)
284# will make doxygen replace the get and set methods by a property in the
285# documentation. This will only work if the methods are indeed getting or
286# setting a simple type. If this is not the case, or you want to show the
287# methods anyway, you should set this option to NO.
288
289IDL_PROPERTY_SUPPORT = YES 56IDL_PROPERTY_SUPPORT = YES
290
291# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
292# tag is set to YES, then doxygen will reuse the documentation of the first
293# member in the group (if any) for the other members of the group. By default
294# all members of a group must be documented explicitly.
295
296DISTRIBUTE_GROUP_DOC = NO 57DISTRIBUTE_GROUP_DOC = NO
297 58GROUP_NESTED_COMPOUNDS = NO
298# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
299# the same type (for instance a group of public functions) to be put as a
300# subgroup of that type (e.g. under the Public Functions section). Set it to
301# NO to prevent subgrouping. Alternatively, this can be done per class using
302# the \nosubgrouping command.
303
304SUBGROUPING = YES 59SUBGROUPING = YES
305
306# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
307# unions are shown inside the group in which they are included (e.g. using
308# @ingroup) instead of on a separate page (for HTML and Man pages) or
309# section (for LaTeX and RTF).
310
311INLINE_GROUPED_CLASSES = NO 60INLINE_GROUPED_CLASSES = NO
312
313# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
314# unions with only public data fields will be shown inline in the documentation
315# of the scope in which they are defined (i.e. file, namespace, or group
316# documentation), provided this scope is documented. If set to NO (the default),
317# structs, classes, and unions are shown on a separate page (for HTML and Man
318# pages) or section (for LaTeX and RTF).
319
320INLINE_SIMPLE_STRUCTS = NO 61INLINE_SIMPLE_STRUCTS = NO
321
322# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
323# is documented as struct, union, or enum with the name of the typedef. So
324# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
325# with name TypeT. When disabled the typedef will appear as a member of a file,
326# namespace, or class. And the struct will be named TypeS. This can typically
327# be useful for C code in case the coding convention dictates that all compound
328# types are typedef'ed and only the typedef is referenced, never the tag name.
329
330TYPEDEF_HIDES_STRUCT = NO 62TYPEDEF_HIDES_STRUCT = NO
331
332# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
333# determine which symbols to keep in memory and which to flush to disk.
334# When the cache is full, less often used symbols will be written to disk.
335# For small to medium size projects (<1000 input files) the default value is
336# probably good enough. For larger projects a too small cache size can cause
337# doxygen to be busy swapping symbols to and from disk most of the time
338# causing a significant performance penalty.
339# If the system has enough physical memory increasing the cache will improve the
340# performance by keeping more symbols in memory. Note that the value works on
341# a logarithmic scale so increasing the size by one will roughly double the
342# memory usage. The cache size is given by this formula:
343# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
344# corresponding to a cache size of 2^16 = 65536 symbols.
345
346SYMBOL_CACHE_SIZE = 0
347
348# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
349# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
350# their name and scope. Since this can be an expensive process and often the
351# same symbol appear multiple times in the code, doxygen keeps a cache of
352# pre-resolved symbols. If the cache is too small doxygen will become slower.
353# If the cache is too large, memory is wasted. The cache size is given by this
354# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
355# corresponding to a cache size of 2^16 = 65536 symbols.
356
357LOOKUP_CACHE_SIZE = 0 63LOOKUP_CACHE_SIZE = 0
358 64NUM_PROC_THREADS = 1
359#--------------------------------------------------------------------------- 65#---------------------------------------------------------------------------
360# Build related configuration options 66# Build related configuration options
361#--------------------------------------------------------------------------- 67#---------------------------------------------------------------------------
362
363# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
364# documentation are documented, even if no documentation was available.
365# Private class members and static file members will be hidden unless
366# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
367
368EXTRACT_ALL = YES 68EXTRACT_ALL = YES
369
370# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
371# will be included in the documentation.
372
373EXTRACT_PRIVATE = YES 69EXTRACT_PRIVATE = YES
374 70EXTRACT_PRIV_VIRTUAL = YES
375# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation. 71EXTRACT_PACKAGE = YES
376
377EXTRACT_PACKAGE = NO
378
379# If the EXTRACT_STATIC tag is set to YES all static members of a file
380# will be included in the documentation.
381
382EXTRACT_STATIC = YES 72EXTRACT_STATIC = YES
383
384# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
385# defined locally in source files will be included in the documentation.
386# If set to NO only classes defined in header files are included.
387
388EXTRACT_LOCAL_CLASSES = YES 73EXTRACT_LOCAL_CLASSES = YES
389
390# This flag is only useful for Objective-C code. When set to YES local
391# methods, which are defined in the implementation section but not in
392# the interface are included in the documentation.
393# If set to NO (the default) only methods in the interface are included.
394
395EXTRACT_LOCAL_METHODS = YES 74EXTRACT_LOCAL_METHODS = YES
396 75EXTRACT_ANON_NSPACES = YES
397# If this flag is set to YES, the members of anonymous namespaces will be 76RESOLVE_UNNAMED_PARAMS = YES
398# extracted and appear in the documentation as a namespace called
399# 'anonymous_namespace{file}', where file will be replaced with the base
400# name of the file that contains the anonymous namespace. By default
401# anonymous namespaces are hidden.
402
403EXTRACT_ANON_NSPACES = NO
404
405# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
406# undocumented members of documented classes, files or namespaces.
407# If set to NO (the default) these members will be included in the
408# various overviews, but no documentation section is generated.
409# This option has no effect if EXTRACT_ALL is enabled.
410
411HIDE_UNDOC_MEMBERS = NO 77HIDE_UNDOC_MEMBERS = NO
412
413# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
414# undocumented classes that are normally visible in the class hierarchy.
415# If set to NO (the default) these classes will be included in the various
416# overviews. This option has no effect if EXTRACT_ALL is enabled.
417
418HIDE_UNDOC_CLASSES = NO 78HIDE_UNDOC_CLASSES = NO
419
420# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
421# friend (class|struct|union) declarations.
422# If set to NO (the default) these declarations will be included in the
423# documentation.
424
425HIDE_FRIEND_COMPOUNDS = NO 79HIDE_FRIEND_COMPOUNDS = NO
426
427# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
428# documentation blocks found inside the body of a function.
429# If set to NO (the default) these blocks will be appended to the
430# function's detailed documentation block.
431
432HIDE_IN_BODY_DOCS = NO 80HIDE_IN_BODY_DOCS = NO
433
434# The INTERNAL_DOCS tag determines if documentation
435# that is typed after a \internal command is included. If the tag is set
436# to NO (the default) then the documentation will be excluded.
437# Set it to YES to include the internal documentation.
438
439INTERNAL_DOCS = YES 81INTERNAL_DOCS = YES
440
441# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
442# file names in lower-case letters. If set to YES upper-case letters are also
443# allowed. This is useful if you have classes or files whose names only differ
444# in case and if your file system supports case sensitive file names. Windows
445# and Mac users are advised to set this option to NO.
446
447CASE_SENSE_NAMES = YES 82CASE_SENSE_NAMES = YES
448
449# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
450# will show members with their full class and namespace scopes in the
451# documentation. If set to YES the scope will be hidden.
452
453HIDE_SCOPE_NAMES = NO 83HIDE_SCOPE_NAMES = NO
454 84HIDE_COMPOUND_REFERENCE= NO
455# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 85SHOW_HEADERFILE = YES
456# will put a list of the files that are included by a file in the documentation
457# of that file.
458
459SHOW_INCLUDE_FILES = YES 86SHOW_INCLUDE_FILES = YES
460 87SHOW_GROUPED_MEMB_INC = NO
461# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
462# will list include files with double quotes in the documentation
463# rather than with sharp brackets.
464
465FORCE_LOCAL_INCLUDES = NO 88FORCE_LOCAL_INCLUDES = NO
466
467# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
468# is inserted in the documentation for inline members.
469
470INLINE_INFO = YES 89INLINE_INFO = YES
471
472# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
473# will sort the (detailed) documentation of file and class members
474# alphabetically by member name. If set to NO the members will appear in
475# declaration order.
476
477SORT_MEMBER_DOCS = YES 90SORT_MEMBER_DOCS = YES
478
479# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
480# brief documentation of file, namespace and class members alphabetically
481# by member name. If set to NO (the default) the members will appear in
482# declaration order.
483
484SORT_BRIEF_DOCS = NO 91SORT_BRIEF_DOCS = NO
485
486# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
487# will sort the (brief and detailed) documentation of class members so that
488# constructors and destructors are listed first. If set to NO (the default)
489# the constructors will appear in the respective orders defined by
490# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
491# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
492# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
493
494SORT_MEMBERS_CTORS_1ST = NO 92SORT_MEMBERS_CTORS_1ST = NO
495
496# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
497# hierarchy of group names into alphabetical order. If set to NO (the default)
498# the group names will appear in their defined order.
499
500SORT_GROUP_NAMES = NO 93SORT_GROUP_NAMES = NO
501
502# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
503# sorted by fully-qualified names, including namespaces. If set to
504# NO (the default), the class list will be sorted only by class name,
505# not including the namespace part.
506# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
507# Note: This option applies only to the class list, not to the
508# alphabetical list.
509
510SORT_BY_SCOPE_NAME = NO 94SORT_BY_SCOPE_NAME = NO
511
512# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
513# do proper type resolution of all parameters of a function it will reject a
514# match between the prototype and the implementation of a member function even
515# if there is only one candidate or it is obvious which candidate to choose
516# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
517# will still accept a match between prototype and implementation in such cases.
518
519STRICT_PROTO_MATCHING = NO 95STRICT_PROTO_MATCHING = NO
520
521# The GENERATE_TODOLIST tag can be used to enable (YES) or
522# disable (NO) the todo list. This list is created by putting \todo
523# commands in the documentation.
524
525GENERATE_TODOLIST = YES 96GENERATE_TODOLIST = YES
526
527# The GENERATE_TESTLIST tag can be used to enable (YES) or
528# disable (NO) the test list. This list is created by putting \test
529# commands in the documentation.
530
531GENERATE_TESTLIST = YES 97GENERATE_TESTLIST = YES
532
533# The GENERATE_BUGLIST tag can be used to enable (YES) or
534# disable (NO) the bug list. This list is created by putting \bug
535# commands in the documentation.
536
537GENERATE_BUGLIST = YES 98GENERATE_BUGLIST = YES
538
539# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
540# disable (NO) the deprecated list. This list is created by putting
541# \deprecated commands in the documentation.
542
543GENERATE_DEPRECATEDLIST= YES 99GENERATE_DEPRECATEDLIST= YES
544
545# The ENABLED_SECTIONS tag can be used to enable conditional
546# documentation sections, marked by \if sectionname ... \endif.
547
548ENABLED_SECTIONS = 100ENABLED_SECTIONS =
549
550# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
551# the initial value of a variable or macro consists of for it to appear in
552# the documentation. If the initializer consists of more lines than specified
553# here it will be hidden. Use a value of 0 to hide initializers completely.
554# The appearance of the initializer of individual variables and macros in the
555# documentation can be controlled using \showinitializer or \hideinitializer
556# command in the documentation regardless of this setting.
557
558MAX_INITIALIZER_LINES = 30 101MAX_INITIALIZER_LINES = 30
559
560# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
561# at the bottom of the documentation of classes and structs. If set to YES the
562# list will mention the files that were used to generate the documentation.
563
564SHOW_USED_FILES = YES 102SHOW_USED_FILES = YES
565
566# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
567# This will remove the Files entry from the Quick Index and from the
568# Folder Tree View (if specified). The default is YES.
569
570SHOW_FILES = YES 103SHOW_FILES = YES
571
572# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
573# Namespaces page.
574# This will remove the Namespaces entry from the Quick Index
575# and from the Folder Tree View (if specified). The default is YES.
576
577SHOW_NAMESPACES = YES 104SHOW_NAMESPACES = YES
578
579# The FILE_VERSION_FILTER tag can be used to specify a program or script that
580# doxygen should invoke to get the current version for each file (typically from
581# the version control system). Doxygen will invoke the program by executing (via
582# popen()) the command <command> <input-file>, where <command> is the value of
583# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
584# provided by doxygen. Whatever the program writes to standard output
585# is used as the file version. See the manual for examples.
586
587FILE_VERSION_FILTER = 105FILE_VERSION_FILTER =
588
589# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
590# by doxygen. The layout file controls the global structure of the generated
591# output files in an output format independent way. The create the layout file
592# that represents doxygen's defaults, run doxygen with the -l option.
593# You can optionally specify a file name after the option, if omitted
594# DoxygenLayout.xml will be used as the name of the layout file.
595
596LAYOUT_FILE = 106LAYOUT_FILE =
597
598# The CITE_BIB_FILES tag can be used to specify one or more bib files
599# containing the references data. This must be a list of .bib files. The
600# .bib extension is automatically appended if omitted. Using this command
601# requires the bibtex tool to be installed. See also
602# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
603# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
604# feature you need bibtex and perl available in the search path.
605
606CITE_BIB_FILES = 107CITE_BIB_FILES =
607
608#--------------------------------------------------------------------------- 108#---------------------------------------------------------------------------
609# configuration options related to warning and progress messages 109# Configuration options related to warning and progress messages
610#--------------------------------------------------------------------------- 110#---------------------------------------------------------------------------
611
612# The QUIET tag can be used to turn on/off the messages that are generated
613# by doxygen. Possible values are YES and NO. If left blank NO is used.
614
615QUIET = NO 111QUIET = NO
616
617# The WARNINGS tag can be used to turn on/off the warning messages that are
618# generated by doxygen. Possible values are YES and NO. If left blank
619# NO is used.
620
621WARNINGS = YES 112WARNINGS = YES
622
623# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
624# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
625# automatically be disabled.
626
627WARN_IF_UNDOCUMENTED = YES 113WARN_IF_UNDOCUMENTED = YES
628
629# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
630# potential errors in the documentation, such as not documenting some
631# parameters in a documented function, or documenting parameters that
632# don't exist or using markup commands wrongly.
633
634WARN_IF_DOC_ERROR = YES 114WARN_IF_DOC_ERROR = YES
635 115WARN_IF_INCOMPLETE_DOC = YES
636# The WARN_NO_PARAMDOC option can be enabled to get warnings for
637# functions that are documented, but have no documentation for their parameters
638# or return value. If set to NO (the default) doxygen will only warn about
639# wrong or incomplete parameter documentation, but not about the absence of
640# documentation.
641
642WARN_NO_PARAMDOC = YES 116WARN_NO_PARAMDOC = YES
643 117WARN_AS_ERROR = NO
644# The WARN_FORMAT tag determines the format of the warning messages that
645# doxygen can produce. The string should contain the $file, $line, and $text
646# tags, which will be replaced by the file and line number from which the
647# warning originated and the warning text. Optionally the format may contain
648# $version, which will be replaced by the version of the file (if it could
649# be obtained via FILE_VERSION_FILTER)
650
651WARN_FORMAT = "$file:$line: $text" 118WARN_FORMAT = "$file:$line: $text"
652 119WARN_LINE_FORMAT = "at line $line of file $file"
653# The WARN_LOGFILE tag can be used to specify a file to which warning
654# and error messages should be written. If left blank the output is written
655# to stderr.
656
657WARN_LOGFILE = Doxywarn 120WARN_LOGFILE = Doxywarn
658
659#--------------------------------------------------------------------------- 121#---------------------------------------------------------------------------
660# configuration options related to the input files 122# Configuration options related to the input files
661#--------------------------------------------------------------------------- 123#---------------------------------------------------------------------------
662
663# The INPUT tag can be used to specify the files and/or directories that contain
664# documented source files. You may enter file names like "myfile.cpp" or
665# directories like "/usr/src/myproject". Separate the files or directories
666# with spaces.
667
668INPUT = src \ 124INPUT = src \
669 src/doxy \ 125 src/doxy \
670 src/stable \ 126 src/stable \
671 src/unstable \ 127 src/unstable \
672 src/experimental 128 src/experimental
673
674# This tag can be used to specify the character encoding of the source files
675# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
676# also the default input encoding. Doxygen uses libiconv (or the iconv built
677# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
678# the list of possible encodings.
679
680INPUT_ENCODING = UTF-8 129INPUT_ENCODING = UTF-8
681
682# If the value of the INPUT tag contains directories, you can use the
683# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
684# and *.h) to filter out the source-files in the directories. If left
685# blank the following patterns are tested:
686# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
687# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
688# *.f90 *.f *.for *.vhd *.vhdl
689
690FILE_PATTERNS = *.c \ 130FILE_PATTERNS = *.c \
691 *.cc \ 131 *.cc \
692 *.cxx \ 132 *.cxx \
@@ -733,1119 +173,225 @@ FILE_PATTERNS = *.c \
733 *.moc \ 173 *.moc \
734 *.xpm \ 174 *.xpm \
735 *.dox 175 *.dox
736
737# The RECURSIVE tag can be used to turn specify whether or not subdirectories
738# should be searched for input files as well. Possible values are YES and NO.
739# If left blank NO is used.
740
741RECURSIVE = NO 176RECURSIVE = NO
742
743# The EXCLUDE tag can be used to specify files and/or directories that should be
744# excluded from the INPUT source files. This way you can easily exclude a
745# subdirectory from a directory tree whose root is specified with the INPUT tag.
746# Note that relative paths are relative to the directory from which doxygen is
747# run.
748
749EXCLUDE = 177EXCLUDE =
750
751# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
752# directories that are symbolic links (a Unix file system feature) are excluded
753# from the input.
754
755EXCLUDE_SYMLINKS = NO 178EXCLUDE_SYMLINKS = NO
756
757# If the value of the INPUT tag contains directories, you can use the
758# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
759# certain files from those directories. Note that the wildcards are matched
760# against the file with absolute path, so to exclude all test directories
761# for example use the pattern */test/*
762
763EXCLUDE_PATTERNS = 179EXCLUDE_PATTERNS =
764
765# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
766# (namespaces, classes, functions, etc.) that should be excluded from the
767# output. The symbol name can be a fully qualified name, a word, or if the
768# wildcard * is used, a substring. Examples: ANamespace, AClass,
769# AClass::ANamespace, ANamespace::*Test
770
771EXCLUDE_SYMBOLS = 180EXCLUDE_SYMBOLS =
772
773# The EXAMPLE_PATH tag can be used to specify one or more files or
774# directories that contain example code fragments that are included (see
775# the \include command).
776
777EXAMPLE_PATH = 181EXAMPLE_PATH =
778
779# If the value of the EXAMPLE_PATH tag contains directories, you can use the
780# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
781# and *.h) to filter out the source-files in the directories. If left
782# blank all files are included.
783
784EXAMPLE_PATTERNS = * 182EXAMPLE_PATTERNS = *
785
786# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
787# searched for input files to be used with the \include or \dontinclude
788# commands irrespective of the value of the RECURSIVE tag.
789# Possible values are YES and NO. If left blank NO is used.
790
791EXAMPLE_RECURSIVE = NO 183EXAMPLE_RECURSIVE = NO
792
793# The IMAGE_PATH tag can be used to specify one or more files or
794# directories that contain image that are included in the documentation (see
795# the \image command).
796
797IMAGE_PATH = 184IMAGE_PATH =
798
799# The INPUT_FILTER tag can be used to specify a program that doxygen should
800# invoke to filter for each input file. Doxygen will invoke the filter program
801# by executing (via popen()) the command <filter> <input-file>, where <filter>
802# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
803# input file. Doxygen will then use the output that the filter program writes
804# to standard output.
805# If FILTER_PATTERNS is specified, this tag will be
806# ignored.
807
808INPUT_FILTER = 185INPUT_FILTER =
809
810# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
811# basis.
812# Doxygen will compare the file name with each pattern and apply the
813# filter if there is a match.
814# The filters are a list of the form:
815# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
816# info on how filters are used. If FILTER_PATTERNS is empty or if
817# non of the patterns match the file name, INPUT_FILTER is applied.
818
819FILTER_PATTERNS = 186FILTER_PATTERNS =
820
821# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
822# INPUT_FILTER) will be used to filter the input files when producing source
823# files to browse (i.e. when SOURCE_BROWSER is set to YES).
824
825FILTER_SOURCE_FILES = NO 187FILTER_SOURCE_FILES = NO
826
827# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
828# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
829# and it is also possible to disable source filtering for a specific pattern
830# using *.ext= (so without naming a filter). This option only has effect when
831# FILTER_SOURCE_FILES is enabled.
832
833FILTER_SOURCE_PATTERNS = 188FILTER_SOURCE_PATTERNS =
834 189USE_MDFILE_AS_MAINPAGE =
835#--------------------------------------------------------------------------- 190#---------------------------------------------------------------------------
836# configuration options related to source browsing 191# Configuration options related to source browsing
837#--------------------------------------------------------------------------- 192#---------------------------------------------------------------------------
838
839# If the SOURCE_BROWSER tag is set to YES then a list of source files will
840# be generated. Documented entities will be cross-referenced with these sources.
841# Note: To get rid of all source code in the generated output, make sure also
842# VERBATIM_HEADERS is set to NO.
843
844SOURCE_BROWSER = YES 193SOURCE_BROWSER = YES
845
846# Setting the INLINE_SOURCES tag to YES will include the body
847# of functions and classes directly in the documentation.
848
849INLINE_SOURCES = NO 194INLINE_SOURCES = NO
850
851# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
852# doxygen to hide any special comment blocks from generated source code
853# fragments. Normal C and C++ comments will always remain visible.
854
855STRIP_CODE_COMMENTS = YES 195STRIP_CODE_COMMENTS = YES
856
857# If the REFERENCED_BY_RELATION tag is set to YES
858# then for each documented function all documented
859# functions referencing it will be listed.
860
861REFERENCED_BY_RELATION = YES 196REFERENCED_BY_RELATION = YES
862
863# If the REFERENCES_RELATION tag is set to YES
864# then for each documented function all documented entities
865# called/used by that function will be listed.
866
867REFERENCES_RELATION = YES 197REFERENCES_RELATION = YES
868
869# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
870# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
871# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
872# link to the source code.
873# Otherwise they will link to the documentation.
874
875REFERENCES_LINK_SOURCE = YES 198REFERENCES_LINK_SOURCE = YES
876 199SOURCE_TOOLTIPS = YES
877# If the USE_HTAGS tag is set to YES then the references to source code
878# will point to the HTML generated by the htags(1) tool instead of doxygen
879# built-in source browser. The htags tool is part of GNU's global source
880# tagging system (see http://www.gnu.org/software/global/global.html). You
881# will need version 4.8.6 or higher.
882
883USE_HTAGS = NO 200USE_HTAGS = NO
884
885# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
886# will generate a verbatim copy of the header file for each class for
887# which an include is specified. Set to NO to disable this.
888
889VERBATIM_HEADERS = YES 201VERBATIM_HEADERS = YES
890 202CLANG_ASSISTED_PARSING = YES
203CLANG_ADD_INC_PATHS = YES
204CLANG_OPTIONS =
205CLANG_DATABASE_PATH =
891#--------------------------------------------------------------------------- 206#---------------------------------------------------------------------------
892# configuration options related to the alphabetical class index 207# Configuration options related to the alphabetical class index
893#--------------------------------------------------------------------------- 208#---------------------------------------------------------------------------
894
895# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
896# of all compounds will be generated. Enable this if the project
897# contains a lot of classes, structs, unions or interfaces.
898
899ALPHABETICAL_INDEX = YES 209ALPHABETICAL_INDEX = YES
900
901# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
902# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
903# in which this list will be split (can be a number in the range [1..20])
904
905COLS_IN_ALPHA_INDEX = 4
906
907# In case all classes in a project start with a common prefix, all
908# classes will be put under the same header in the alphabetical index.
909# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
910# should be ignored while generating the index headers.
911
912IGNORE_PREFIX = 210IGNORE_PREFIX =
913
914#--------------------------------------------------------------------------- 211#---------------------------------------------------------------------------
915# configuration options related to the HTML output 212# Configuration options related to the HTML output
916#--------------------------------------------------------------------------- 213#---------------------------------------------------------------------------
917
918# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
919# generate HTML output.
920
921GENERATE_HTML = YES 214GENERATE_HTML = YES
922
923# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
924# If a relative path is entered the value of OUTPUT_DIRECTORY will be
925# put in front of it. If left blank `html' will be used as the default path.
926
927HTML_OUTPUT = html 215HTML_OUTPUT = html
928
929# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
930# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
931# doxygen will generate files with .html extension.
932
933HTML_FILE_EXTENSION = .html 216HTML_FILE_EXTENSION = .html
934
935# The HTML_HEADER tag can be used to specify a personal HTML header for
936# each generated HTML page. If it is left blank doxygen will generate a
937# standard header. Note that when using a custom header you are responsible
938# for the proper inclusion of any scripts and style sheets that doxygen
939# needs, which is dependent on the configuration options used.
940# It is advised to generate a default header using "doxygen -w html
941# header.html footer.html stylesheet.css YourConfigFile" and then modify
942# that header. Note that the header is subject to change so you typically
943# have to redo this when upgrading to a newer version of doxygen or when
944# changing the value of configuration settings such as GENERATE_TREEVIEW!
945
946HTML_HEADER = 217HTML_HEADER =
947
948# The HTML_FOOTER tag can be used to specify a personal HTML footer for
949# each generated HTML page. If it is left blank doxygen will generate a
950# standard footer.
951
952HTML_FOOTER = 218HTML_FOOTER =
953
954# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
955# style sheet that is used by each HTML page. It can be used to
956# fine-tune the look of the HTML output. If the tag is left blank doxygen
957# will generate a default style sheet. Note that doxygen will try to copy
958# the style sheet file to the HTML output directory, so don't put your own
959# style sheet in the HTML output directory as well, or it will be erased!
960
961HTML_STYLESHEET = 219HTML_STYLESHEET =
962 220HTML_EXTRA_STYLESHEET =
963# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
964# other source files which should be copied to the HTML output directory. Note
965# that these files will be copied to the base HTML output directory. Use the
966# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
967# files. In the HTML_STYLESHEET file, use the file name only. Also note that
968# the files will be copied as-is; there are no commands or markers available.
969
970HTML_EXTRA_FILES = 221HTML_EXTRA_FILES =
971
972# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
973# Doxygen will adjust the colors in the style sheet and background images
974# according to this color. Hue is specified as an angle on a colorwheel,
975# see http://en.wikipedia.org/wiki/Hue for more information.
976# For instance the value 0 represents red, 60 is yellow, 120 is green,
977# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
978# The allowed range is 0 to 359.
979
980HTML_COLORSTYLE_HUE = 220 222HTML_COLORSTYLE_HUE = 220
981
982# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
983# the colors in the HTML output. For a value of 0 the output will use
984# grayscales only. A value of 255 will produce the most vivid colors.
985
986HTML_COLORSTYLE_SAT = 100 223HTML_COLORSTYLE_SAT = 100
987
988# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
989# the luminance component of the colors in the HTML output. Values below
990# 100 gradually make the output lighter, whereas values above 100 make
991# the output darker. The value divided by 100 is the actual gamma applied,
992# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
993# and 100 does not change the gamma.
994
995HTML_COLORSTYLE_GAMMA = 80 224HTML_COLORSTYLE_GAMMA = 80
996
997# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
998# page will contain the date and time when the page was generated. Setting
999# this to NO can help when comparing the output of multiple runs.
1000
1001HTML_TIMESTAMP = YES 225HTML_TIMESTAMP = YES
1002 226HTML_DYNAMIC_MENUS = YES
1003# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
1004# documentation will contain sections that can be hidden and shown after the
1005# page has loaded.
1006
1007HTML_DYNAMIC_SECTIONS = YES 227HTML_DYNAMIC_SECTIONS = YES
1008
1009# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
1010# entries shown in the various tree structured indices initially; the user
1011# can expand and collapse entries dynamically later on. Doxygen will expand
1012# the tree to such a level that at most the specified number of entries are
1013# visible (unless a fully collapsed tree already exceeds this amount).
1014# So setting the number of entries 1 will produce a full collapsed tree by
1015# default. 0 is a special value representing an infinite number of entries
1016# and will result in a full expanded tree by default.
1017
1018HTML_INDEX_NUM_ENTRIES = 100 228HTML_INDEX_NUM_ENTRIES = 100
1019
1020# If the GENERATE_DOCSET tag is set to YES, additional index files
1021# will be generated that can be used as input for Apple's Xcode 3
1022# integrated development environment, introduced with OSX 10.5 (Leopard).
1023# To create a documentation set, doxygen will generate a Makefile in the
1024# HTML output directory. Running make will produce the docset in that
1025# directory and running "make install" will install the docset in
1026# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
1027# it at startup.
1028# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
1029# for more information.
1030
1031GENERATE_DOCSET = NO 229GENERATE_DOCSET = NO
1032
1033# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
1034# feed. A documentation feed provides an umbrella under which multiple
1035# documentation sets from a single provider (such as a company or product suite)
1036# can be grouped.
1037
1038DOCSET_FEEDNAME = "Doxygen generated docs" 230DOCSET_FEEDNAME = "Doxygen generated docs"
1039 231DOCSET_FEEDURL =
1040# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
1041# should uniquely identify the documentation set bundle. This should be a
1042# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
1043# will append .docset to the name.
1044
1045DOCSET_BUNDLE_ID = org.doxygen.Project 232DOCSET_BUNDLE_ID = org.doxygen.Project
1046
1047# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
1048# the documentation publisher. This should be a reverse domain-name style
1049# string, e.g. com.mycompany.MyDocSet.documentation.
1050
1051DOCSET_PUBLISHER_ID = org.doxygen.Publisher 233DOCSET_PUBLISHER_ID = org.doxygen.Publisher
1052
1053# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
1054
1055DOCSET_PUBLISHER_NAME = Publisher 234DOCSET_PUBLISHER_NAME = Publisher
1056
1057# If the GENERATE_HTMLHELP tag is set to YES, additional index files
1058# will be generated that can be used as input for tools like the
1059# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
1060# of the generated HTML documentation.
1061
1062GENERATE_HTMLHELP = NO 235GENERATE_HTMLHELP = NO
1063
1064# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
1065# be used to specify the file name of the resulting .chm file. You
1066# can add a path in front of the file if the result should not be
1067# written to the html output directory.
1068
1069CHM_FILE = 236CHM_FILE =
1070
1071# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
1072# be used to specify the location (absolute path including file name) of
1073# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
1074# the HTML help compiler on the generated index.hhp.
1075
1076HHC_LOCATION = 237HHC_LOCATION =
1077
1078# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
1079# controls if a separate .chi index file is generated (YES) or that
1080# it should be included in the master .chm file (NO).
1081
1082GENERATE_CHI = NO 238GENERATE_CHI = NO
1083
1084# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
1085# is used to encode HtmlHelp index (hhk), content (hhc) and project file
1086# content.
1087
1088CHM_INDEX_ENCODING = 239CHM_INDEX_ENCODING =
1089
1090# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
1091# controls whether a binary table of contents is generated (YES) or a
1092# normal table of contents (NO) in the .chm file.
1093
1094BINARY_TOC = NO 240BINARY_TOC = NO
1095
1096# The TOC_EXPAND flag can be set to YES to add extra items for group members
1097# to the contents of the HTML help documentation and to the tree view.
1098
1099TOC_EXPAND = NO 241TOC_EXPAND = NO
1100
1101# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
1102# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
1103# that can be used as input for Qt's qhelpgenerator to generate a
1104# Qt Compressed Help (.qch) of the generated HTML documentation.
1105
1106GENERATE_QHP = NO 242GENERATE_QHP = NO
1107
1108# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
1109# be used to specify the file name of the resulting .qch file.
1110# The path specified is relative to the HTML output folder.
1111
1112QCH_FILE = 243QCH_FILE =
1113
1114# The QHP_NAMESPACE tag specifies the namespace to use when generating
1115# Qt Help Project output. For more information please see
1116# http://doc.trolltech.com/qthelpproject.html#namespace
1117
1118QHP_NAMESPACE = 244QHP_NAMESPACE =
1119
1120# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
1121# Qt Help Project output. For more information please see
1122# http://doc.trolltech.com/qthelpproject.html#virtual-folders
1123
1124QHP_VIRTUAL_FOLDER = doc 245QHP_VIRTUAL_FOLDER = doc
1125
1126# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
1127# add. For more information please see
1128# http://doc.trolltech.com/qthelpproject.html#custom-filters
1129
1130QHP_CUST_FILTER_NAME = 246QHP_CUST_FILTER_NAME =
1131
1132# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
1133# custom filter to add. For more information please see
1134# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
1135# Qt Help Project / Custom Filters</a>.
1136
1137QHP_CUST_FILTER_ATTRS = 247QHP_CUST_FILTER_ATTRS =
1138
1139# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
1140# project's
1141# filter section matches.
1142# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
1143# Qt Help Project / Filter Attributes</a>.
1144
1145QHP_SECT_FILTER_ATTRS = 248QHP_SECT_FILTER_ATTRS =
1146
1147# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
1148# be used to specify the location of Qt's qhelpgenerator.
1149# If non-empty doxygen will try to run qhelpgenerator on the generated
1150# .qhp file.
1151
1152QHG_LOCATION = 249QHG_LOCATION =
1153
1154# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
1155# will be generated, which together with the HTML files, form an Eclipse help
1156# plugin. To install this plugin and make it available under the help contents
1157# menu in Eclipse, the contents of the directory containing the HTML and XML
1158# files needs to be copied into the plugins directory of eclipse. The name of
1159# the directory within the plugins directory should be the same as
1160# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
1161# the help appears.
1162
1163GENERATE_ECLIPSEHELP = NO 250GENERATE_ECLIPSEHELP = NO
1164
1165# A unique identifier for the eclipse help plugin. When installing the plugin
1166# the directory name containing the HTML and XML files should also have
1167# this name.
1168
1169ECLIPSE_DOC_ID = org.doxygen.Project 251ECLIPSE_DOC_ID = org.doxygen.Project
1170
1171# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
1172# at top of each HTML page. The value NO (the default) enables the index and
1173# the value YES disables it. Since the tabs have the same information as the
1174# navigation tree you can set this option to NO if you already set
1175# GENERATE_TREEVIEW to YES.
1176
1177DISABLE_INDEX = NO 252DISABLE_INDEX = NO
1178
1179# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
1180# structure should be generated to display hierarchical information.
1181# If the tag value is set to YES, a side panel will be generated
1182# containing a tree-like index structure (just like the one that
1183# is generated for HTML Help). For this to work a browser that supports
1184# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
1185# Windows users are probably better off using the HTML help feature.
1186# Since the tree basically has the same information as the tab index you
1187# could consider to set DISABLE_INDEX to NO when enabling this option.
1188
1189GENERATE_TREEVIEW = NO 253GENERATE_TREEVIEW = NO
1190 254FULL_SIDEBAR = NO
1191# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
1192# (range [0,1..20]) that doxygen will group on one line in the generated HTML
1193# documentation. Note that a value of 0 will completely suppress the enum
1194# values from appearing in the overview section.
1195
1196ENUM_VALUES_PER_LINE = 4 255ENUM_VALUES_PER_LINE = 4
1197
1198# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
1199# used to set the initial width (in pixels) of the frame in which the tree
1200# is shown.
1201
1202TREEVIEW_WIDTH = 250 256TREEVIEW_WIDTH = 250
1203
1204# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
1205# links to external symbols imported via tag files in a separate window.
1206
1207EXT_LINKS_IN_WINDOW = NO 257EXT_LINKS_IN_WINDOW = NO
1208 258OBFUSCATE_EMAILS = YES
1209# Use this tag to change the font size of Latex formulas included 259HTML_FORMULA_FORMAT = png
1210# as images in the HTML documentation. The default is 10. Note that
1211# when you change the font size after a successful doxygen run you need
1212# to manually remove any form_*.png images from the HTML output directory
1213# to force them to be regenerated.
1214
1215FORMULA_FONTSIZE = 10 260FORMULA_FONTSIZE = 10
1216
1217# Use the FORMULA_TRANPARENT tag to determine whether or not the images
1218# generated for formulas are transparent PNGs. Transparent PNGs are
1219# not supported properly for IE 6.0, but are supported on all modern browsers.
1220# Note that when changing this option you need to delete any form_*.png files
1221# in the HTML output before the changes have effect.
1222
1223FORMULA_TRANSPARENT = YES 261FORMULA_TRANSPARENT = YES
1224 262FORMULA_MACROFILE =
1225# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
1226# (see http://www.mathjax.org) which uses client side Javascript for the
1227# rendering instead of using prerendered bitmaps. Use this if you do not
1228# have LaTeX installed or if you want to formulas look prettier in the HTML
1229# output. When enabled you may also need to install MathJax separately and
1230# configure the path to it using the MATHJAX_RELPATH option.
1231
1232USE_MATHJAX = NO 263USE_MATHJAX = NO
1233 264MATHJAX_VERSION = MathJax_2
1234# When MathJax is enabled you need to specify the location relative to the 265MATHJAX_FORMAT = HTML-CSS
1235# HTML output directory using the MATHJAX_RELPATH option. The destination
1236# directory should contain the MathJax.js script. For instance, if the mathjax
1237# directory is located at the same level as the HTML output directory, then
1238# MATHJAX_RELPATH should be ../mathjax. The default value points to
1239# the MathJax Content Delivery Network so you can quickly see the result without
1240# installing MathJax.
1241# However, it is strongly recommended to install a local
1242# copy of MathJax from http://www.mathjax.org before deployment.
1243
1244MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest 266MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
1245
1246# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
1247# names that should be enabled during MathJax rendering.
1248
1249MATHJAX_EXTENSIONS = 267MATHJAX_EXTENSIONS =
1250 268MATHJAX_CODEFILE =
1251# When the SEARCHENGINE tag is enabled doxygen will generate a search box
1252# for the HTML output. The underlying search engine uses javascript
1253# and DHTML and should work on any modern browser. Note that when using
1254# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
1255# (GENERATE_DOCSET) there is already a search function so this one should
1256# typically be disabled. For large projects the javascript based search engine
1257# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
1258
1259SEARCHENGINE = NO 269SEARCHENGINE = NO
1260
1261# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
1262# implemented using a PHP enabled web server instead of at the web client
1263# using Javascript. Doxygen will generate the search PHP script and index
1264# file to put on the web server. The advantage of the server
1265# based approach is that it scales better to large projects and allows
1266# full text search. The disadvantages are that it is more difficult to setup
1267# and does not have live searching capabilities.
1268
1269SERVER_BASED_SEARCH = NO 270SERVER_BASED_SEARCH = NO
1270 271EXTERNAL_SEARCH = NO
272SEARCHENGINE_URL =
273SEARCHDATA_FILE = searchdata.xml
274EXTERNAL_SEARCH_ID =
275EXTRA_SEARCH_MAPPINGS =
1271#--------------------------------------------------------------------------- 276#---------------------------------------------------------------------------
1272# configuration options related to the LaTeX output 277# Configuration options related to the LaTeX output
1273#--------------------------------------------------------------------------- 278#---------------------------------------------------------------------------
1274
1275# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
1276# generate Latex output.
1277
1278GENERATE_LATEX = yes 279GENERATE_LATEX = yes
1279
1280# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
1281# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1282# put in front of it. If left blank `latex' will be used as the default path.
1283
1284LATEX_OUTPUT = latex 280LATEX_OUTPUT = latex
1285
1286# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
1287# invoked. If left blank `latex' will be used as the default command name.
1288# Note that when enabling USE_PDFLATEX this option is only used for
1289# generating bitmaps for formulas in the HTML output, but not in the
1290# Makefile that is written to the output directory.
1291
1292LATEX_CMD_NAME = latex 281LATEX_CMD_NAME = latex
1293
1294# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
1295# generate index for LaTeX. If left blank `makeindex' will be used as the
1296# default command name.
1297
1298MAKEINDEX_CMD_NAME = makeindex 282MAKEINDEX_CMD_NAME = makeindex
1299 283LATEX_MAKEINDEX_CMD = makeindex
1300# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
1301# LaTeX documents. This may be useful for small projects and may help to
1302# save some trees in general.
1303
1304COMPACT_LATEX = NO 284COMPACT_LATEX = NO
1305
1306# The PAPER_TYPE tag can be used to set the paper type that is used
1307# by the printer. Possible values are: a4, letter, legal and
1308# executive. If left blank a4wide will be used.
1309
1310PAPER_TYPE = letter 285PAPER_TYPE = letter
1311
1312# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
1313# packages that should be included in the LaTeX output.
1314
1315EXTRA_PACKAGES = 286EXTRA_PACKAGES =
1316
1317# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
1318# the generated latex document. The header should contain everything until
1319# the first chapter. If it is left blank doxygen will generate a
1320# standard header. Notice: only use this tag if you know what you are doing!
1321
1322LATEX_HEADER = 287LATEX_HEADER =
1323
1324# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
1325# the generated latex document. The footer should contain everything after
1326# the last chapter. If it is left blank doxygen will generate a
1327# standard footer. Notice: only use this tag if you know what you are doing!
1328
1329LATEX_FOOTER = 288LATEX_FOOTER =
1330 289LATEX_EXTRA_STYLESHEET =
1331# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 290LATEX_EXTRA_FILES =
1332# is prepared for conversion to pdf (using ps2pdf). The pdf file will
1333# contain links (just like the HTML output) instead of page references
1334# This makes the output suitable for online browsing using a pdf viewer.
1335
1336PDF_HYPERLINKS = YES 291PDF_HYPERLINKS = YES
1337
1338# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
1339# plain latex in the generated Makefile. Set this option to YES to get a
1340# higher quality PDF documentation.
1341
1342USE_PDFLATEX = YES 292USE_PDFLATEX = YES
1343
1344# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
1345# command to the generated LaTeX files. This will instruct LaTeX to keep
1346# running if errors occur, instead of asking the user for help.
1347# This option is also used when generating formulas in HTML.
1348
1349LATEX_BATCHMODE = YES 293LATEX_BATCHMODE = YES
1350
1351# If LATEX_HIDE_INDICES is set to YES then doxygen will not
1352# include the index chapters (such as File Index, Compound Index, etc.)
1353# in the output.
1354
1355LATEX_HIDE_INDICES = NO 294LATEX_HIDE_INDICES = NO
1356
1357# If LATEX_SOURCE_CODE is set to YES then doxygen will include
1358# source code with syntax highlighting in the LaTeX output.
1359# Note that which sources are shown also depends on other settings
1360# such as SOURCE_BROWSER.
1361
1362LATEX_SOURCE_CODE = NO
1363
1364# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
1365# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
1366# http://en.wikipedia.org/wiki/BibTeX for more info.
1367
1368LATEX_BIB_STYLE = plain 295LATEX_BIB_STYLE = plain
1369 296LATEX_TIMESTAMP = NO
297LATEX_EMOJI_DIRECTORY =
1370#--------------------------------------------------------------------------- 298#---------------------------------------------------------------------------
1371# configuration options related to the RTF output 299# Configuration options related to the RTF output
1372#--------------------------------------------------------------------------- 300#---------------------------------------------------------------------------
1373
1374# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
1375# The RTF output is optimized for Word 97 and may not look very pretty with
1376# other RTF readers or editors.
1377
1378GENERATE_RTF = NO 301GENERATE_RTF = NO
1379
1380# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
1381# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1382# put in front of it. If left blank `rtf' will be used as the default path.
1383
1384RTF_OUTPUT = rtf 302RTF_OUTPUT = rtf
1385
1386# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
1387# RTF documents. This may be useful for small projects and may help to
1388# save some trees in general.
1389
1390COMPACT_RTF = NO 303COMPACT_RTF = NO
1391
1392# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
1393# will contain hyperlink fields. The RTF file will
1394# contain links (just like the HTML output) instead of page references.
1395# This makes the output suitable for online browsing using WORD or other
1396# programs which support those fields.
1397# Note: wordpad (write) and others do not support links.
1398
1399RTF_HYPERLINKS = YES 304RTF_HYPERLINKS = YES
1400
1401# Load style sheet definitions from file. Syntax is similar to doxygen's
1402# config file, i.e. a series of assignments. You only have to provide
1403# replacements, missing definitions are set to their default value.
1404
1405RTF_STYLESHEET_FILE = 305RTF_STYLESHEET_FILE =
1406
1407# Set optional variables used in the generation of an rtf document.
1408# Syntax is similar to doxygen's config file.
1409
1410RTF_EXTENSIONS_FILE = 306RTF_EXTENSIONS_FILE =
1411
1412#--------------------------------------------------------------------------- 307#---------------------------------------------------------------------------
1413# configuration options related to the man page output 308# Configuration options related to the man page output
1414#--------------------------------------------------------------------------- 309#---------------------------------------------------------------------------
1415
1416# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
1417# generate man pages
1418
1419GENERATE_MAN = NO 310GENERATE_MAN = NO
1420
1421# The MAN_OUTPUT tag is used to specify where the man pages will be put.
1422# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1423# put in front of it. If left blank `man' will be used as the default path.
1424
1425MAN_OUTPUT = man 311MAN_OUTPUT = man
1426
1427# The MAN_EXTENSION tag determines the extension that is added to
1428# the generated man pages (default is the subroutine's section .3)
1429
1430MAN_EXTENSION = .3 312MAN_EXTENSION = .3
1431 313MAN_SUBDIR =
1432# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
1433# then it will generate one additional man file for each entity
1434# documented in the real man page(s). These additional files
1435# only source the real man page, but without them the man command
1436# would be unable to find the correct page. The default is NO.
1437
1438MAN_LINKS = NO 314MAN_LINKS = NO
1439
1440#--------------------------------------------------------------------------- 315#---------------------------------------------------------------------------
1441# configuration options related to the XML output 316# Configuration options related to the XML output
1442#--------------------------------------------------------------------------- 317#---------------------------------------------------------------------------
1443
1444# If the GENERATE_XML tag is set to YES Doxygen will
1445# generate an XML file that captures the structure of
1446# the code including all documentation.
1447
1448GENERATE_XML = NO 318GENERATE_XML = NO
1449
1450# The XML_OUTPUT tag is used to specify where the XML pages will be put.
1451# If a relative path is entered the value of OUTPUT_DIRECTORY will be
1452# put in front of it. If left blank `xml' will be used as the default path.
1453
1454XML_OUTPUT = xml 319XML_OUTPUT = xml
1455
1456# The XML_SCHEMA tag can be used to specify an XML schema,
1457# which can be used by a validating XML parser to check the
1458# syntax of the XML files.
1459
1460XML_SCHEMA =
1461
1462# The XML_DTD tag can be used to specify an XML DTD,
1463# which can be used by a validating XML parser to check the
1464# syntax of the XML files.
1465
1466XML_DTD =
1467
1468# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
1469# dump the program listings (including syntax highlighting
1470# and cross-referencing information) to the XML output. Note that
1471# enabling this will significantly increase the size of the XML output.
1472
1473XML_PROGRAMLISTING = YES 320XML_PROGRAMLISTING = YES
1474 321XML_NS_MEMB_FILE_SCOPE = NO
1475#--------------------------------------------------------------------------- 322#---------------------------------------------------------------------------
1476# configuration options for the AutoGen Definitions output 323# Configuration options related to the DOCBOOK output
324#---------------------------------------------------------------------------
325GENERATE_DOCBOOK = NO
326DOCBOOK_OUTPUT = docbook
327#---------------------------------------------------------------------------
328# Configuration options for the AutoGen Definitions output
1477#--------------------------------------------------------------------------- 329#---------------------------------------------------------------------------
1478
1479# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
1480# generate an AutoGen Definitions (see autogen.sf.net) file
1481# that captures the structure of the code including all
1482# documentation. Note that this feature is still experimental
1483# and incomplete at the moment.
1484
1485GENERATE_AUTOGEN_DEF = NO 330GENERATE_AUTOGEN_DEF = NO
1486
1487#--------------------------------------------------------------------------- 331#---------------------------------------------------------------------------
1488# configuration options related to the Perl module output 332# Configuration options related to the Perl module output
1489#--------------------------------------------------------------------------- 333#---------------------------------------------------------------------------
1490
1491# If the GENERATE_PERLMOD tag is set to YES Doxygen will
1492# generate a Perl module file that captures the structure of
1493# the code including all documentation. Note that this
1494# feature is still experimental and incomplete at the
1495# moment.
1496
1497GENERATE_PERLMOD = NO 334GENERATE_PERLMOD = NO
1498
1499# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
1500# the necessary Makefile rules, Perl scripts and LaTeX code to be able
1501# to generate PDF and DVI output from the Perl module output.
1502
1503PERLMOD_LATEX = YES 335PERLMOD_LATEX = YES
1504
1505# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
1506# nicely formatted so it can be parsed by a human reader.
1507# This is useful
1508# if you want to understand what is going on.
1509# On the other hand, if this
1510# tag is set to NO the size of the Perl module output will be much smaller
1511# and Perl will parse it just the same.
1512
1513PERLMOD_PRETTY = YES 336PERLMOD_PRETTY = YES
1514
1515# The names of the make variables in the generated doxyrules.make file
1516# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
1517# This is useful so different doxyrules.make files included by the same
1518# Makefile don't overwrite each other's variables.
1519
1520PERLMOD_MAKEVAR_PREFIX = 337PERLMOD_MAKEVAR_PREFIX =
1521
1522#--------------------------------------------------------------------------- 338#---------------------------------------------------------------------------
1523# Configuration options related to the preprocessor 339# Configuration options related to the preprocessor
1524#--------------------------------------------------------------------------- 340#---------------------------------------------------------------------------
1525
1526# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
1527# evaluate all C-preprocessor directives found in the sources and include
1528# files.
1529
1530ENABLE_PREPROCESSING = YES 341ENABLE_PREPROCESSING = YES
1531
1532# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
1533# names in the source code. If set to NO (the default) only conditional
1534# compilation will be performed. Macro expansion can be done in a controlled
1535# way by setting EXPAND_ONLY_PREDEF to YES.
1536
1537MACRO_EXPANSION = YES 342MACRO_EXPANSION = YES
1538
1539# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
1540# then the macro expansion is limited to the macros specified with the
1541# PREDEFINED and EXPAND_AS_DEFINED tags.
1542
1543EXPAND_ONLY_PREDEF = NO 343EXPAND_ONLY_PREDEF = NO
1544
1545# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
1546# pointed to by INCLUDE_PATH will be searched when a #include is found.
1547
1548SEARCH_INCLUDES = YES 344SEARCH_INCLUDES = YES
1549
1550# The INCLUDE_PATH tag can be used to specify one or more directories that
1551# contain include files that are not input files but should be processed by
1552# the preprocessor.
1553
1554INCLUDE_PATH = 345INCLUDE_PATH =
1555
1556# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
1557# patterns (like *.h and *.hpp) to filter out the header-files in the
1558# directories. If left blank, the patterns specified with FILE_PATTERNS will
1559# be used.
1560
1561INCLUDE_FILE_PATTERNS = 346INCLUDE_FILE_PATTERNS =
1562
1563# The PREDEFINED tag can be used to specify one or more macro names that
1564# are defined before the preprocessor is started (similar to the -D option of
1565# gcc). The argument of the tag is a list of macros of the form: name
1566# or name=definition (no spaces). If the definition and the = are
1567# omitted =1 is assumed. To prevent a macro definition from being
1568# undefined via #undef or recursively expanded use the := operator
1569# instead of the = operator.
1570
1571PREDEFINED = 347PREDEFINED =
1572
1573# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
1574# this tag can be used to specify a list of macro names that should be expanded.
1575# The macro definition that is found in the sources will be used.
1576# Use the PREDEFINED tag if you want to use a different macro definition that
1577# overrules the definition found in the source code.
1578
1579EXPAND_AS_DEFINED = 348EXPAND_AS_DEFINED =
1580
1581# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
1582# doxygen's preprocessor will remove all references to function-like macros
1583# that are alone on a line, have an all uppercase name, and do not end with a
1584# semicolon, because these will confuse the parser if not removed.
1585
1586SKIP_FUNCTION_MACROS = YES 349SKIP_FUNCTION_MACROS = YES
1587
1588#--------------------------------------------------------------------------- 350#---------------------------------------------------------------------------
1589# Configuration::additions related to external references 351# Configuration options related to external references
1590#--------------------------------------------------------------------------- 352#---------------------------------------------------------------------------
1591
1592# The TAGFILES option can be used to specify one or more tagfiles. For each
1593# tag file the location of the external documentation should be added. The
1594# format of a tag file without this location is as follows:
1595#
1596# TAGFILES = file1 file2 ...
1597# Adding location for the tag files is done as follows:
1598#
1599# TAGFILES = file1=loc1 "file2 = loc2" ...
1600# where "loc1" and "loc2" can be relative or absolute paths
1601# or URLs. Note that each tag file must have a unique name (where the name does
1602# NOT include the path). If a tag file is not located in the directory in which
1603# doxygen is run, you must also specify the path to the tagfile here.
1604
1605TAGFILES = 353TAGFILES =
1606
1607# When a file name is specified after GENERATE_TAGFILE, doxygen will create
1608# a tag file that is based on the input files it reads.
1609
1610GENERATE_TAGFILE = 354GENERATE_TAGFILE =
1611
1612# If the ALLEXTERNALS tag is set to YES all external classes will be listed
1613# in the class index. If set to NO only the inherited external classes
1614# will be listed.
1615
1616ALLEXTERNALS = NO 355ALLEXTERNALS = NO
1617
1618# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
1619# in the modules index. If set to NO, only the current project's groups will
1620# be listed.
1621
1622EXTERNAL_GROUPS = YES 356EXTERNAL_GROUPS = YES
1623 357EXTERNAL_PAGES = YES
1624# The PERL_PATH should be the absolute path and name of the perl script
1625# interpreter (i.e. the result of `which perl').
1626
1627PERL_PATH = /usr/bin/perl
1628
1629#--------------------------------------------------------------------------- 358#---------------------------------------------------------------------------
1630# Configuration options related to the dot tool 359# Configuration options related to the dot tool
1631#--------------------------------------------------------------------------- 360#---------------------------------------------------------------------------
1632 361DIA_PATH =
1633# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
1634# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
1635# or super classes. Setting the tag to NO turns the diagrams off. Note that
1636# this option also works with HAVE_DOT disabled, but it is recommended to
1637# install and use dot, since it yields more powerful graphs.
1638
1639CLASS_DIAGRAMS = YES
1640
1641# You can define message sequence charts within doxygen comments using the \msc
1642# command. Doxygen will then run the mscgen tool (see
1643# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
1644# documentation. The MSCGEN_PATH tag allows you to specify the directory where
1645# the mscgen tool resides. If left empty the tool is assumed to be found in the
1646# default search path.
1647
1648MSCGEN_PATH =
1649
1650# If set to YES, the inheritance and collaboration graphs will hide
1651# inheritance and usage relations if the target is undocumented
1652# or is not a class.
1653
1654HIDE_UNDOC_RELATIONS = YES 362HIDE_UNDOC_RELATIONS = YES
1655
1656# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
1657# available from the path. This tool is part of Graphviz, a graph visualization
1658# toolkit from AT&T and Lucent Bell Labs. The other options in this section
1659# have no effect if this option is set to NO (the default)
1660
1661HAVE_DOT = YES 363HAVE_DOT = YES
1662
1663# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
1664# allowed to run in parallel. When set to 0 (the default) doxygen will
1665# base this on the number of processors available in the system. You can set it
1666# explicitly to a value larger than 0 to get control over the balance
1667# between CPU load and processing speed.
1668
1669DOT_NUM_THREADS = 0 364DOT_NUM_THREADS = 0
1670
1671# By default doxygen will use the Helvetica font for all dot files that
1672# doxygen generates. When you want a differently looking font you can specify
1673# the font name using DOT_FONTNAME. You need to make sure dot is able to find
1674# the font, which can be done by putting it in a standard location or by setting
1675# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
1676# directory containing the font.
1677
1678DOT_FONTNAME = FreeSans 365DOT_FONTNAME = FreeSans
1679
1680# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
1681# The default size is 10pt.
1682
1683DOT_FONTSIZE = 10 366DOT_FONTSIZE = 10
1684
1685# By default doxygen will tell dot to use the Helvetica font.
1686# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
1687# set the path where dot can find it.
1688
1689DOT_FONTPATH = 367DOT_FONTPATH =
1690
1691# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
1692# will generate a graph for each documented class showing the direct and
1693# indirect inheritance relations. Setting this tag to YES will force the
1694# CLASS_DIAGRAMS tag to NO.
1695
1696CLASS_GRAPH = YES 368CLASS_GRAPH = YES
1697
1698# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
1699# will generate a graph for each documented class showing the direct and
1700# indirect implementation dependencies (inheritance, containment, and
1701# class references variables) of the class with other documented classes.
1702
1703COLLABORATION_GRAPH = YES 369COLLABORATION_GRAPH = YES
1704
1705# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
1706# will generate a graph for groups, showing the direct groups dependencies
1707
1708GROUP_GRAPHS = YES 370GROUP_GRAPHS = YES
1709
1710# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
1711# collaboration diagrams in a style similar to the OMG's Unified Modeling
1712# Language.
1713
1714UML_LOOK = NO 371UML_LOOK = NO
1715
1716# If the UML_LOOK tag is enabled, the fields and methods are shown inside
1717# the class node. If there are many fields or methods and many nodes the
1718# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
1719# threshold limits the number of items for each type to make the size more
1720# managable. Set this to 0 for no limit. Note that the threshold may be
1721# exceeded by 50% before the limit is enforced.
1722
1723UML_LIMIT_NUM_FIELDS = 10 372UML_LIMIT_NUM_FIELDS = 10
1724 373DOT_UML_DETAILS = NO
1725# If set to YES, the inheritance and collaboration graphs will show the 374DOT_WRAP_THRESHOLD = 17
1726# relations between templates and their instances.
1727
1728TEMPLATE_RELATIONS = NO 375TEMPLATE_RELATIONS = NO
1729
1730# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
1731# tags are set to YES then doxygen will generate a graph for each documented
1732# file showing the direct and indirect include dependencies of the file with
1733# other documented files.
1734
1735INCLUDE_GRAPH = YES 376INCLUDE_GRAPH = YES
1736
1737# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
1738# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
1739# documented header file showing the documented files that directly or
1740# indirectly include this file.
1741
1742INCLUDED_BY_GRAPH = YES 377INCLUDED_BY_GRAPH = YES
1743 378CALL_GRAPH = YES
1744# If the CALL_GRAPH and HAVE_DOT options are set to YES then 379CALLER_GRAPH = YES
1745# doxygen will generate a call dependency graph for every global function
1746# or class method. Note that enabling this option will significantly increase
1747# the time of a run. So in most cases it will be better to enable call graphs
1748# for selected functions only using the \callgraph command.
1749
1750CALL_GRAPH = NO
1751
1752# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
1753# doxygen will generate a caller dependency graph for every global function
1754# or class method. Note that enabling this option will significantly increase
1755# the time of a run. So in most cases it will be better to enable caller
1756# graphs for selected functions only using the \callergraph command.
1757
1758CALLER_GRAPH = NO
1759
1760# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
1761# will generate a graphical hierarchy of all classes instead of a textual one.
1762
1763GRAPHICAL_HIERARCHY = YES 380GRAPHICAL_HIERARCHY = YES
1764
1765# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
1766# then doxygen will show the dependencies a directory has on other directories
1767# in a graphical way. The dependency relations are determined by the #include
1768# relations between the files in the directories.
1769
1770DIRECTORY_GRAPH = NO 381DIRECTORY_GRAPH = NO
1771 382DIR_GRAPH_MAX_DEPTH = 1
1772# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
1773# generated by dot. Possible values are svg, png, jpg, or gif.
1774# If left blank png will be used. If you choose svg you need to set
1775# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
1776# visible in IE 9+ (other browsers do not have this requirement).
1777
1778DOT_IMAGE_FORMAT = png 383DOT_IMAGE_FORMAT = png
1779 384INTERACTIVE_SVG = YES
1780# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
1781# enable generation of interactive SVG images that allow zooming and panning.
1782# Note that this requires a modern browser other than Internet Explorer.
1783# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
1784# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
1785# visible. Older versions of IE do not have SVG support.
1786
1787INTERACTIVE_SVG = NO
1788
1789# The tag DOT_PATH can be used to specify the path where the dot tool can be
1790# found. If left blank, it is assumed the dot tool can be found in the path.
1791
1792DOT_PATH = 385DOT_PATH =
1793
1794# The DOTFILE_DIRS tag can be used to specify one or more directories that
1795# contain dot files that are included in the documentation (see the
1796# \dotfile command).
1797
1798DOTFILE_DIRS = 386DOTFILE_DIRS =
1799
1800# The MSCFILE_DIRS tag can be used to specify one or more directories that
1801# contain msc files that are included in the documentation (see the
1802# \mscfile command).
1803
1804MSCFILE_DIRS = 387MSCFILE_DIRS =
1805 388DIAFILE_DIRS =
1806# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 389PLANTUML_JAR_PATH =
1807# nodes that will be shown in the graph. If the number of nodes in a graph 390PLANTUML_CFG_FILE =
1808# becomes larger than this value, doxygen will truncate the graph, which is 391PLANTUML_INCLUDE_PATH =
1809# visualized by representing a node as a red box. Note that doxygen if the
1810# number of direct children of the root node in a graph is already larger than
1811# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
1812# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
1813
1814DOT_GRAPH_MAX_NODES = 50 392DOT_GRAPH_MAX_NODES = 50
1815
1816# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
1817# graphs generated by dot. A depth value of 3 means that only nodes reachable
1818# from the root by following a path via at most 3 edges will be shown. Nodes
1819# that lay further from the root node will be omitted. Note that setting this
1820# option to 1 or 2 may greatly reduce the computation time needed for large
1821# code bases. Also note that the size of a graph can be further restricted by
1822# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
1823
1824MAX_DOT_GRAPH_DEPTH = 1000 393MAX_DOT_GRAPH_DEPTH = 1000
1825
1826# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
1827# background. This is disabled by default, because dot on Windows does not
1828# seem to support this out of the box. Warning: Depending on the platform used,
1829# enabling this option may lead to badly anti-aliased labels on the edges of
1830# a graph (i.e. they become hard to read).
1831
1832DOT_TRANSPARENT = NO 394DOT_TRANSPARENT = NO
1833
1834# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
1835# files in one run (i.e. multiple -o and -T options on the command line). This
1836# makes dot run faster, but since only newer versions of dot (>1.8.10)
1837# support this, this feature is disabled by default.
1838
1839DOT_MULTI_TARGETS = NO 395DOT_MULTI_TARGETS = NO
1840
1841# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
1842# generate a legend page explaining the meaning of the various boxes and
1843# arrows in the dot generated graphs.
1844
1845GENERATE_LEGEND = YES 396GENERATE_LEGEND = YES
1846
1847# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
1848# remove the intermediate dot files that are used to generate
1849# the various graphs.
1850
1851DOT_CLEANUP = YES 397DOT_CLEANUP = YES
diff --git a/src/experimental/debugmutex.cpp b/src/experimental/debugmutex.cpp
new file mode 100644
index 0000000..2b61ae2
--- /dev/null
+++ b/src/experimental/debugmutex.cpp
@@ -0,0 +1,78 @@
1#include "bu/debugmutex.h"
2
3#include "bu/exceptionbase.h"
4
5Bu::DebugMutex::DebugMutex()
6{
7}
8
9Bu::DebugMutex::~DebugMutex()
10{
11}
12
13int Bu::DebugMutex::lock()
14{
15 pthread_t self = pthread_self();
16 mState.lock();
17 bool bFound = false;
18 for( ThreadList::iterator i = lThreads.begin(); i; i++ )
19 {
20 if( (*i) == self )
21 {
22 bFound = true;
23 if( (*i).bLocked == true )
24 {
25 throw Bu::ExceptionBase( Bu::String("Double lock in thread: %1").arg( (*i).sName ).end().getStr() );
26
27 }
28 else
29 {
30 (*i).bLocked = true;
31 }
32 break;
33 }
34 }
35 if( bFound == false )
36 {
37 lThreads.append( ThreadInfo( true ) );
38 }
39 mState.unlock();
40 return Bu::Mutex::lock();
41}
42
43int Bu::DebugMutex::unlock()
44{
45 pthread_t self = pthread_self();
46 mState.lock();
47 bool bFound = false;
48 for( ThreadList::iterator i = lThreads.begin(); i; i++ )
49 {
50 if( (*i) == self )
51 {
52 bFound = true;
53 if( (*i).bLocked == false )
54 {
55 throw Bu::ExceptionBase( Bu::String("Unlock in thread that did not lock: %1").arg( (*i).sName ).end().getStr() );
56
57 }
58 else
59 {
60 (*i).bLocked = false;
61 }
62 break;
63 }
64 }
65 if( bFound == false )
66 {
67 ThreadInfo info( false );
68 throw Bu::ExceptionBase( Bu::String("Unlock in thread that never locked mutex: %1").arg( info.sName ).end().getStr() );
69 }
70 mState.unlock();
71 return Bu::Mutex::unlock();
72}
73
74int Bu::DebugMutex::trylock()
75{
76 return Bu::Mutex::trylock();
77}
78
diff --git a/src/experimental/debugmutex.h b/src/experimental/debugmutex.h
new file mode 100644
index 0000000..ca8ef9f
--- /dev/null
+++ b/src/experimental/debugmutex.h
@@ -0,0 +1,102 @@
1/*
2 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_DEBUG_MUTEX_H
9#define BU_DEBUG_MUTEX_H
10
11#include "bu/mutex.h"
12#include "bu/list.h"
13#include "bu/string.h"
14
15namespace Bu
16{
17 /**
18 * Simple mutex wrapper. Currently this doesn't do anything extra for you
19 * except keep all of the functionality together in an OO sorta' way and
20 * keep you from having to worry about cleaning up your mutexes properly,
21 * or initing them.
22 *@ingroup Threading
23 */
24 class DebugMutex : public Mutex
25 {
26 public:
27 /**
28 * Create an unlocked mutex.
29 */
30 DebugMutex();
31
32 /**
33 * Destroy a mutex. This can only be done when a mutex is unlocked.
34 * Failure to unlock before destroying a mutex object could cause it to
35 * wait for the mutex to unlock, the odds of which are usually farily
36 * low at deconstruction time.
37 */
38 virtual ~DebugMutex();
39
40 /**
41 * Lock the mutex. This causes all future calls to lock on this
42 * instance of mutex to block until the first thread that called mutex
43 * unlocks it. At that point the next thread that called lock will get
44 * a chance to go to work. Because of the nature of a mutex lock it is
45 * a very bad idea to do any kind of serious or rather time consuming
46 * computation within a locked section. This can cause thread-deadlock
47 * and your program may hang.
48 */
49 virtual int lock();
50
51 /**
52 * Unlock the mutex. This allows the next thread that asked for a lock
53 * to lock the mutex and continue with execution.
54 */
55 virtual int unlock();
56
57 /**
58 * Try to lock the mutex. This is the option to go with if you cannot
59 * avoid putting lengthy operations within a locked section. trylock
60 * will attempt to lock the mutex, if the mutex is already locked this
61 * function returns immediately with an error code.
62 */
63 virtual int trylock();
64
65 private:
66 Bu::Mutex mState;
67
68 class ThreadInfo
69 {
70 public:
71 ThreadInfo( bool bLocked=false ) :
72 idThread( pthread_self() ),
73 bLocked( bLocked )
74 {
75 char buf[64];
76 if( pthread_getname_np( idThread, buf, 64 ) == 0 )
77 sName = buf;
78 }
79 ~ThreadInfo() {}
80
81 bool operator==( const ThreadInfo &rhs )
82 {
83 return pthread_equal( idThread, rhs.idThread );
84 }
85
86 bool operator==( const pthread_t &rhs )
87 {
88 return pthread_equal( idThread, rhs );
89 }
90
91 pthread_t idThread;
92 Bu::String sName;
93 bool bLocked;
94 };
95 typedef Bu::List<ThreadInfo> ThreadList;
96 ThreadList lThreads;
97 };
98}
99
100#endif
101
102
diff --git a/src/stable/file.cpp b/src/stable/file.cpp
index 05e4af1..55766ea 100644
--- a/src/stable/file.cpp
+++ b/src/stable/file.cpp
@@ -142,6 +142,16 @@ bool Bu::File::isEos()
142 142
143bool Bu::File::canRead() 143bool Bu::File::canRead()
144{ 144{
145 return isReadable();
146}
147
148bool Bu::File::canWrite()
149{
150 return isWritable();
151}
152
153bool Bu::File::isReadable()
154{
145#ifdef WIN32 155#ifdef WIN32
146 return true; 156 return true;
147#else 157#else
@@ -152,7 +162,7 @@ bool Bu::File::canRead()
152#endif 162#endif
153} 163}
154 164
155bool Bu::File::canWrite() 165bool Bu::File::isWritable()
156{ 166{
157#ifdef WIN32 167#ifdef WIN32
158 return true; 168 return true;
@@ -164,16 +174,6 @@ bool Bu::File::canWrite()
164#endif 174#endif
165} 175}
166 176
167bool Bu::File::isReadable()
168{
169 return true;
170}
171
172bool Bu::File::isWritable()
173{
174 return true;
175}
176
177bool Bu::File::isSeekable() 177bool Bu::File::isSeekable()
178{ 178{
179 return true; 179 return true;
diff --git a/src/stable/mutex.h b/src/stable/mutex.h
index d9e8910..8034974 100644
--- a/src/stable/mutex.h
+++ b/src/stable/mutex.h
@@ -33,7 +33,7 @@ namespace Bu
33 * wait for the mutex to unlock, the odds of which are usually farily 33 * wait for the mutex to unlock, the odds of which are usually farily
34 * low at deconstruction time. 34 * low at deconstruction time.
35 */ 35 */
36 ~Mutex(); 36 virtual ~Mutex();
37 37
38 /** 38 /**
39 * Lock the mutex. This causes all future calls to lock on this 39 * Lock the mutex. This causes all future calls to lock on this
@@ -44,13 +44,13 @@ namespace Bu
44 * computation within a locked section. This can cause thread-deadlock 44 * computation within a locked section. This can cause thread-deadlock
45 * and your program may hang. 45 * and your program may hang.
46 */ 46 */
47 int lock(); 47 virtual int lock();
48 48
49 /** 49 /**
50 * Unlock the mutex. This allows the next thread that asked for a lock 50 * Unlock the mutex. This allows the next thread that asked for a lock
51 * to lock the mutex and continue with execution. 51 * to lock the mutex and continue with execution.
52 */ 52 */
53 int unlock(); 53 virtual int unlock();
54 54
55 /** 55 /**
56 * Try to lock the mutex. This is the option to go with if you cannot 56 * Try to lock the mutex. This is the option to go with if you cannot
@@ -58,7 +58,7 @@ namespace Bu
58 * will attempt to lock the mutex, if the mutex is already locked this 58 * will attempt to lock the mutex, if the mutex is already locked this
59 * function returns immediately with an error code. 59 * function returns immediately with an error code.
60 */ 60 */
61 int trylock(); 61 virtual int trylock();
62 62
63 protected: 63 protected:
64 pthread_mutex_t mutex; /**< The internal mutex reference. */ 64 pthread_mutex_t mutex; /**< The internal mutex reference. */
diff --git a/src/stable/myriad.cpp b/src/stable/myriad.cpp
index 86f651e..53250c2 100644
--- a/src/stable/myriad.cpp
+++ b/src/stable/myriad.cpp
@@ -1,24 +1,25 @@
1/*
2 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/config.h"
9#include "bu/myriad.h" 1#include "bu/myriad.h"
10#include "bu/stream.h"
11#include "bu/myriadstream.h" 2#include "bu/myriadstream.h"
3
4#include "bu/membuf.h"
12#include "bu/mutexlocker.h" 5#include "bu/mutexlocker.h"
13#include <stdio.h> 6#include "bu/util.h"
14 7
15#include "bu/sio.h" 8#include "bu/sio.h"
16using Bu::sio;
17using Bu::Fmt;
18 9
19#define Myriad_MAGIC_CODE ((unsigned char *)"\x0a\xd3\xfa\x84") 10#define Myriad_MAGIC_CODE ((unsigned char *)"\x0a\xd3\xfa\x84")
20 11
21#define TRACE( x ) Bu::println("%1:%2: %3: %4 - %5").arg(__FILE__).arg( __LINE__ ).arg(__PRETTY_FUNCTION__).arg(sStore.getLocation()).arg(x) 12#define MyriadRead( target, size ) if( rBacking.read( target, size ) < size ) \
13{ \
14 throw Bu::MyriadException( Bu::MyriadException::invalidFormat, \
15 "Insufficient data reading myriad data from backing stream."); \
16} (void)0
17
18#define ReqRead( stream, target, size ) if( stream.read( target, size ) < size ) \
19{ \
20 throw Bu::MyriadException( Bu::MyriadException::invalidFormat, \
21 "Insufficient data reading from myriad stream."); \
22} (void)0
22 23
23namespace Bu 24namespace Bu
24{ 25{
@@ -28,779 +29,844 @@ namespace Bu
28 } 29 }
29} 30}
30 31
31Bu::Myriad::Myriad( Bu::Stream &sStore, int iBlockSize, int iPreallocate ) : 32Bu::Myriad::Myriad( Bu::Stream &rBacking, int iBlockSize,
32 sStore( sStore ), 33 int iPreallocateBlocks ) :
34 rBacking( rBacking ),
33 iBlockSize( iBlockSize ), 35 iBlockSize( iBlockSize ),
34 iBlocks( 0 ), 36 iBlockCount( 0 ),
35 iUsed( 0 ), 37 bIsNewStream( true ),
36 bHeaderChanged( false ) 38 bStructureChanged( false ),
39 iLastUsedIndex( -1 )
37{ 40{
38 try 41 if( !rBacking.isSeekable() )
39 { 42 {
40 initialize(); 43 throw Bu::MyriadException( Bu::MyriadException::invalidBackingStream,
44 "Myriad backing stream must be random access (seekable).");
41 } 45 }
42 catch( Bu::MyriadException &e ) 46 if( rBacking.getSize() == 0 )
43 { 47 {
44 if( e.getErrorCode() == MyriadException::emptyStream ) 48 createMyriad( iBlockSize, iPreallocateBlocks );
45 { 49 }
46 initialize( iBlockSize, iPreallocate ); 50 else
47 } 51 {
48 else 52 loadMyriad();
49 {
50 throw;
51 }
52 } 53 }
53} 54}
54 55
55Bu::Myriad::~Myriad() 56Bu::Myriad::~Myriad()
56{ 57{
57 mActiveBlocks.lock(); 58 writeHeader();
58 TRACE("mActiveBlocks locked."); 59}
59 if( !hActiveBlocks.isEmpty() ) 60
60 { 61Bu::MyriadStream Bu::Myriad::create( Bu::Myriad::Mode eMode,
61 sio << "Bu::Myriad::~Myriad(): Error: There are " 62 int32_t iPreallocateBytes )
62 << hActiveBlocks.getSize() << " unsynced blocks!" << sio.nl; 63{
63 } 64 Bu::MutexLocker l( mAccess );
64 TRACE("mActiveBlocks unlocking...");
65 mActiveBlocks.unlock();
66 sync();
67 65
68 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 66 Stream *pStream = new Stream( *this, ++iLastUsedIndex, 0 );
67 int iBlocks = std::max(1, blkDiv( iPreallocateBytes, iBlockSize ));
68 for( int j = 0; j < iBlocks; j++ )
69 { 69 {
70 delete *i; 70 pStream->aBlocks.append( __allocateBlock() );
71 } 71 }
72 mhStream.lock();
73 hStream.insert( pStream->iStream, pStream );
74 mhStream.unlock();
75 bStructureChanged = true;
76
77 return Bu::MyriadStream( *this, pStream, eMode&ReadWrite );
72} 78}
73 79
74void Bu::Myriad::sync() 80Bu::MyriadStream Bu::Myriad::open( Bu::Myriad::StreamId iStream,
81 Bu::Myriad::Mode eMode )
75{ 82{
76 updateHeader(); 83 Stream *pStream = NULL;
77 84 Bu::MutexLocker l( mhStream );
78 mActiveBlocks.lock(); 85 if( (eMode&Create) )
79 TRACE("mActiveBlocks locked.");
80 for( BlockHash::iterator i = hActiveBlocks.begin(); i; i++ )
81 { 86 {
82 if( (*i)->bChanged ) 87 if( hStream.has( iStream ) )
88 {
89 if( (eMode&Exclusive) )
90 {
91 throw Bu::MyriadException( MyriadException::noSuchStream,
92 "Stream exists.");
93 }
94 }
95 else
83 { 96 {
84 syncBlock( *i ); 97 Bu::MutexLocker l( mAccess );
98 if( iStream >= iLastUsedIndex )
99 {
100 iLastUsedIndex = iStream;
101 }
102 pStream = new Stream( *this, iStream, 0 );
103 pStream->aBlocks.append( __allocateBlock() );
104 hStream.insert( pStream->iStream, pStream );
105 bStructureChanged = true;
85 } 106 }
86 } 107 }
87 TRACE("mActiveBlocks unlocked..."); 108 if( !hStream.has( iStream ) )
88 mActiveBlocks.unlock();
89}
90
91void Bu::Myriad::initialize()
92{
93 MutexLocker mLock( mHeader );
94 TRACE("mHeader locked.");
95 lFreeBlocks.clear();
96 sStore.setPosEnd( 0 );
97 Bu::size iSize = sStore.tell();
98 sStore.setPos( 0 );
99
100 unsigned char buf[4];
101 if( sStore.read( buf, 4 ) < 4 )
102 { 109 {
103 TRACE("mHeader unlocked..."); 110 throw Bu::MyriadException( MyriadException::noSuchStream,
104 throw MyriadException( MyriadException::emptyStream, 111 "No such stream.");
105 "Input stream appears to be empty.");
106 } 112 }
107 if( memcmp( buf, Myriad_MAGIC_CODE, 4 ) )
108 { 113 {
109 TRACE("mHeader unlocked..."); 114 Bu::MutexLocker l2( mBacking );
110 throw MyriadException( MyriadException::invalidFormat, 115 if( (eMode&Write) && !rBacking.isWritable() )
111 "Stream does not appear to be a valid Myriad format."); 116 {
117 throw Bu::MyriadException( MyriadException::badMode,
118 "Backing stream does not support writing.");
119 }
112 } 120 }
113 sStore.read( buf, 2 ); 121 if( pStream == NULL )
114 if( buf[0] != 1 )
115 { 122 {
116 TRACE("mHeader unlocked..."); 123 pStream = hStream.get( iStream );
117 throw MyriadException( MyriadException::badVersion,
118 "We can only handle version 1 for now.");
119 } 124 }
120 if( buf[1] != 32 ) 125 if( (eMode&Truncate) )
121 { 126 {
122 TRACE("mHeader unlocked..."); 127 pStream->setSize( 0 );
123 throw MyriadException( MyriadException::invalidWordSize,
124 "We can only handle 32-bit words at the moment.");
125 } 128 }
126 sStore.read( &iBlockSize, 4 ); 129 return Bu::MyriadStream( *this, pStream, eMode );
127 int iStreams; 130}
128 sStore.read( &iStreams, 4 );
129
130 iBlocks = iSize/iBlockSize;
131 //sio << "Myriad: iSize=" << iSize << ", iBlockSize=" << iBlockSize
132 // << ", iBlocks=" << iBlocks << ", iStreams=" << iStreams << sio.nl;
133 131
134 int iHeaderSize = 14 + 8 + 4; 132Bu::Myriad::StreamId Bu::Myriad::allocate()
135 int iHeaderBlocks = 0; //blkDiv( iHeaderSize+4, iBlockSize ); 133{
134 Bu::MutexLocker l( mAccess );
136 135
137 while( iHeaderSize > iHeaderBlocks*iBlockSize ) 136 Stream *pStream = new Stream( *this, ++iLastUsedIndex, 0 );
138 { 137 mhStream.lock();
139 iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize ); 138 hStream.insert( pStream->iStream, pStream );
140 iHeaderSize = 14 + 8 + 4*iHeaderBlocks; 139 mhStream.unlock();
141 } 140 bStructureChanged = true;
142 141
143 //sio << "Myriad: iHeaderSize=" << iHeaderSize 142 return pStream->iStream;
144 // << ", iHeaderBlocks=" << iHeaderBlocks << sio.nl; 143}
145 144
146 Stream *pFakeHdr = new Stream; 145void Bu::Myriad::erase( Bu::Myriad::StreamId iStream )
147 pFakeHdr->iId = 0; 146{
148 pFakeHdr->iSize = iHeaderSize; 147 // For now, let's prevent you from erasing a stream if it's open.
149 for( int j = 0; j < iHeaderBlocks; j++ ) 148 Bu::MutexLocker l( mhStream );
149 if( !hStream.has( iStream ) )
150 { 150 {
151 pFakeHdr->aBlocks.append( j ); 151 throw Bu::MyriadException( Bu::MyriadException::noSuchStream,
152 "No such stream exists.");
152 } 153 }
153 154 Stream *pStream = hStream.get( iStream );
154// sio << "Blocks: " << iBlocks << " (size = " << iSize << "/" << iBlockSize
155// << ")" << sio.nl;
156 Bu::BitString bsBlockUsed( iBlocks, false );
157 bsBlockUsed.clear();
158
159// bool bCanSkip = false; // Can skip around, post initial header stream i/o
160 MyriadStream *pIn = new MyriadStream( *this, pFakeHdr );
161 pIn->setPos( sStore.tell() );
162 for( int j = 0; j < iStreams; j++ )
163 { 155 {
164 aStreams.append( new Stream() ); 156 Bu::MutexLocker sl( pStream->mAccess );
165 Stream &s = *aStreams[j]; 157 if( pStream->iOpenCount > 0 )
166 pIn->read( &s.iId, 4 );
167 pIn->read( &s.iSize, 4 );
168 int iSBlocks = blkDiv(s.iSize, iBlockSize);
169 // sio << "Myriad: - Stream::iId=" << s.iId
170 // << ", Stream::iSize=" << s.iSize
171 // << ", Stream::aBlocks=" << iSBlocks
172 // << ", pIn->tell()=" << pIn->tell() << sio.nl;
173 for( int k = 0; k < iSBlocks; k++ )
174 { 158 {
175 int iBId; 159 throw Bu::MyriadException( Bu::MyriadException::streamOpen,
176 pIn->read( &iBId, 4 ); 160 "Cannot currently erase a stream while it is open.");
177 // sio << "Myriad: - iBId=" << iBId
178 // << ", iStartPos=" << iBId*iBlockSize
179 // << ", pIn->tell()=" << pIn->tell() << sio.nl;
180 s.aBlocks.append( iBId );
181 bsBlockUsed.setBit( iBId );
182 iUsed++;
183 if( (j == 0 && k == iHeaderBlocks-1) )
184 {
185 // sio << "Myriad: - End of prepartition, unlocking skipping."
186 // << sio.nl;
187// bCanSkip = true;
188 MyriadStream *pTmp = new MyriadStream( *this, aStreams[0] );
189 // sio << "Myriad - Position = " << pIn->tell() << sio.nl;
190 pTmp->setPos( pIn->tell() );
191 delete pIn;
192 delete pFakeHdr;
193 pIn = pTmp;
194 }
195 } 161 }
196 }
197 delete pIn;
198 162
199 for( int j = 0; j < iBlocks; j++ ) 163 for( Bu::Array<int32_t>::iterator i = pStream->aBlocks.begin(); i; i++ )
200 {
201 if( bsBlockUsed.getBit( j ) == false )
202 { 164 {
203// sio << "Preinitialized block " << j << " is free." << sio.nl; 165 releaseBlock( *i, false );
204 lFreeBlocks.append( j );
205 } 166 }
167 pStream->aBlocks.clear();
168 hStream.erase( iStream );
206 } 169 }
207// sio << "Myriad: Blocks used: " << bsBlockUsed.toString() << sio.nl; 170 delete pStream;
208 TRACE("mHeader unlocked...");
209} 171}
210 172
211void Bu::Myriad::initialize( int iBlockSize, int iPreAllocate ) 173void Bu::Myriad::setSize( Bu::Myriad::StreamId iStream,
174 int32_t iNewSize )
212{ 175{
213 MutexLocker mLock( mHeader ); 176 Stream *pStream;
214 TRACE("mHeader locked.");
215 lFreeBlocks.clear();
216
217 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
218 { 177 {
219 delete *i; 178 Bu::MutexLocker l( mhStream );
220 } 179 pStream = hStream.get( iStream );
221 aStreams.clear();
222 iUsed = 0;
223
224 int iHeaderSize = 14 + 8 + 4;
225 int iHeaderBlocks = 0; //blkDiv( iHeaderSize+4, iBlockSize );
226 char cBuf = 1;
227 int iBuf = 0;
228
229 Stream *pStr = new Stream;
230 pStr->iId = 0;
231
232 while( iHeaderSize > iHeaderBlocks*iBlockSize )
233 {
234 iHeaderBlocks = blkDiv( iHeaderSize+4, iBlockSize );
235 iHeaderSize = 14 + 8 + 4*iHeaderBlocks;
236 } 180 }
181 pStream->setSize( iNewSize );
182}
237 183
238 iPreAllocate += iHeaderBlocks; 184int32_t Bu::Myriad::getSize( StreamId iStream ) const
185{
186 Bu::MutexLocker l( mhStream );
187 return hStream.get( iStream )->getSize();
188}
239 189
240 //sio << "Myriad: iHeaderSize=" << iHeaderSize << ", iBlockSize=" 190bool Bu::Myriad::exists( StreamId iStream ) const
241 // << iBlockSize << ", iHeaderBlocks=" << iHeaderBlocks << sio.nl; 191{
242 192 Bu::MutexLocker l( mhStream );
243// bsBlockUsed.setSize( iPreAllocate, true ); 193 return hStream.has( iStream );
244 iUsed++; 194}
245 195
246 char *pBlock = new char[iBlockSize]; 196Bu::String Bu::Myriad::getLocation() const
247 memset( pBlock, 0, iBlockSize ); 197{
248 for( int j = 0; j < iPreAllocate; j++ ) 198 Bu::MutexLocker l( mAccess );
249 { 199 Bu::MutexLocker l2( mBacking );
250 sStore.write( pBlock, iBlockSize ); 200 return Bu::String("myriad(%1,%2):%3")
251 } 201 .arg( 1 ).arg( iBlockSize ).arg( rBacking.getLocation() );
252 delete[] (char *)pBlock; 202}
253 203
254 sStore.setPos( 0 ); 204int32_t Bu::Myriad::getBlockSize() const
205{
206 Bu::MutexLocker l( mAccess );
207 return iBlockSize;
208}
255 209
256 // Magic number 210int32_t Bu::Myriad::getTotalBlocks() const
257 sStore.write( Myriad_MAGIC_CODE, 4 ); 211{
212 Bu::MutexLocker l( mAccess );
213 return iBlockCount;
214}
258 215
259 // Version (0) 216int32_t Bu::Myriad::getUsedBlocks() const
260 sStore.write( &cBuf, 1 ); 217{
218 Bu::MutexLocker l( mAccess );
219 return iBlockCount-lFreeBlocks.getSize();
220}
261 221
262 // Bits per int 222int32_t Bu::Myriad::getFreeBlocks() const
263 cBuf = 32; 223{
264 sStore.write( &cBuf, 1 ); 224 Bu::MutexLocker l( mAccess );
225 return lFreeBlocks.getSize();
226}
265 227
266 // The size of each block 228int32_t Bu::Myriad::getTotalStreams() const
267 sStore.write( &iBlockSize, 4 ); 229{
230 Bu::MutexLocker l( mhStream );
231 return hStream.getSize();
232}
268 233
269 iBuf = 1; 234int32_t Bu::Myriad::getTotalUsedBytes() const
270 // The number of streams 235{
271 sStore.write( &iBuf, 4 ); 236 Bu::MutexLocker l( mhStream );
272 237 int32_t iTotal = 0;
273 // Stream header 238 for( StreamHash::const_iterator i = hStream.begin(); i; i++ )
274 iBuf = 0;
275 sStore.write( &iBuf, 4 );
276 sStore.write( &iHeaderSize, 4 );
277 for( iBuf = 0; iBuf < iHeaderBlocks; iBuf++ )
278 { 239 {
279 sStore.write( &iBuf, 4 ); 240 iTotal += i.getValue()->getSize();
280 } 241 }
281 242
282 this->iBlockSize = iBlockSize; 243 return iTotal;
283 this->iBlocks = iPreAllocate; 244}
284
285 pStr->iSize = sStore.tell();
286// sio << "Myriad: Actual end of header stream = " << pStr->iSize << sio.nl;
287 245
288 pStr->iSize = iHeaderSize; 246int32_t Bu::Myriad::getTotalUnusedBytes(int32_t iAssumeBlockSize ) const
289 for( int j = 0; j < iHeaderBlocks; j++ ) 247{
248 if( iAssumeBlockSize < 0 )
290 { 249 {
291// sio << "Started block " << j << " is header." << sio.nl; 250 iAssumeBlockSize = getBlockSize();
292 pStr->aBlocks.append( j );
293// bsBlockUsed.setBit( j );
294 iUsed++;
295 } 251 }
296 for( int j = iHeaderBlocks; j < this->iBlocks; j++ ) 252 int32_t iTotal = 0;
297 { 253 {
298// sio << "Started block " << j << " is free." << sio.nl; 254 Bu::MutexLocker l( mhStream );
299 lFreeBlocks.append( j ); 255 for( StreamHash::const_iterator i = hStream.begin(); i; i++ )
256 {
257 if( (i.getValue()->getSize()%iAssumeBlockSize) > 0 )
258 iTotal += iBlockSize-(i.getValue()->getSize()%iAssumeBlockSize);
259 }
300 } 260 }
301 261
302 aStreams.append( pStr ); 262 {
263 Bu::MutexLocker l( mAccess );
264 iTotal += lFreeBlocks.getSize()*iBlockSize;
265 }
303 266
304 //sio << bsBlockUsed.toString() << " - " << pStr->aBlocks << sio.nl; 267 return iTotal;
268}
305 269
306 bHeaderChanged = true; 270Bu::Myriad::StreamIdList Bu::Myriad::getStreamList() const
307 //hStreams.insert( 0, BlockArray( 0 ) ); 271{
308 TRACE("mHeader unlocked..."); 272 mhStream.lock();
273 StreamIdList lIds = hStream.getKeys();
274 mhStream.unlock();
275 lIds.sort();
276 if( lIds.first() == 0 )
277 {
278 lIds.eraseFirst();
279 }
280 return lIds;
309} 281}
310 282
311void Bu::Myriad::updateHeader() 283Bu::BitString Bu::Myriad::buildBlockUseMap() const
312{ 284{
313 MutexLocker mLock( mHeader ); 285 Bu::MutexLocker l( mAccess );
314 TRACE("mHeader locked."); 286 Bu::BitString bsMap( iBlockCount );
287 bsMap.fill();
288 for( IndexList::const_iterator i = lFreeBlocks.begin(); i; i++ )
289 {
290 bsMap.setBit( *i, false );
291 }
292 return bsMap;
293}
315 294
316 if( bHeaderChanged == false ) 295Bu::Myriad::StreamIdArray Bu::Myriad::buildBlockMap() const
296{
297 Bu::MutexLocker l( mAccess );
298 StreamIdArray bm( iBlockCount );
299 for( int j = 0; j < iBlockCount; j++ )
317 { 300 {
318 TRACE("mHeader unlocked..."); 301 bm.append( -1 );
319 return;
320 } 302 }
321 if( !sStore.canWrite() ) 303 Bu::MutexLocker l2( mhStream );
304 for( StreamHash::const_iterator iStream = hStream.begin();
305 iStream; iStream++ )
322 { 306 {
323 TRACE("mHeader unlocked..."); 307 int32_t iId = iStream.getKey();
324 return; 308 Stream *pStream = iStream.getValue();
309 for( Bu::Array<int32_t>::const_iterator iBlock =
310 pStream->aBlocks.begin(); iBlock; iBlock++ )
311 {
312 bm[*iBlock] = iId;
313 }
325 } 314 }
315 return bm;
316}
326 317
327 char cBuf; 318void Bu::Myriad::sync()
328 int iBuf; 319{
320 writeHeader();
321}
329 322
330 //for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 323bool Bu::Myriad::loadMyriad()
331 //{ 324{
332 // sio << "Myriad: Stream " << Fmt(4) << (*i)->iId << ": " << (*i)->aBlocks << sio.nl; 325 //Bu::println("Load myriad!");
333 //} 326 char sMagicCode[4];
327 rBacking.setPos( 0 );
328 MyriadRead( sMagicCode, 4 );
329 if( memcmp( sMagicCode, Myriad_MAGIC_CODE, 4 ) )
330 {
331 throw Bu::MyriadException( Bu::MyriadException::invalidFormat,
332 "Backing stream does not seem to be a Myriad structure.");
333 }
334 uint8_t uVer;
335 uint8_t uBitsPerInt;
336 MyriadRead( &uVer, 1 );
337 if( uVer != 1 )
338 {
339 throw Bu::MyriadException( Bu::MyriadException::invalidFormat,
340 "Only version 1 myriad structures are supported.");
341 }
342 MyriadRead( &uBitsPerInt, 1 );
343 if( uBitsPerInt != 32 )
344 {
345 throw Bu::MyriadException( Bu::MyriadException::invalidFormat,
346 "Only 32 bits per int are supported at this time.");
347 }
348 MyriadRead( &iBlockSize, 4 );
334 349
335 // Compute the new size of the header. 350 iBlockCount = rBacking.getSize()/iBlockSize;
336 int iHeaderSize = 14 + 8*aStreams.getSize(); 351 if( (rBacking.getSize()%iBlockSize) != 0 )
337// sio << "Myriad: updateHeader: aStreams.getSize() = " << aStreams.getSize()
338// << sio.nl;
339 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
340 { 352 {
341 iHeaderSize += 4*(*i)->aBlocks.getSize(); 353 throw Bu::MyriadException( Bu::MyriadException::invalidFormat,
342// sio << "Myriad: updateHeader: (*i)->aBlocks.getSize() = " 354 "Backing stream is not cleanly divisibly by the block size.");
343// << (*i)->aBlocks.getSize() << sio.nl;
344 } 355 }
345 int iNewBlocks = blkDiv( iHeaderSize, iBlockSize ); 356
346 while( iNewBlocks > aStreams[0]->aBlocks.getSize() ) 357 Bu::Hash<int32_t,bool> hUnusedBlocks;
358 for( int32_t j = 0; j < iBlockCount; j++ )
347 { 359 {
348 int iBlock = findEmptyBlock(); 360 hUnusedBlocks.insert( j, true );
349// sio << "Myriad: updateHeader: Appending block " << iBlock
350// << " to header." << sio.nl;
351 aStreams[0]->aBlocks.append( iBlock );
352// bsBlockUsed.setBit( iBlock );
353 iUsed++;
354 iHeaderSize += 4;
355 iNewBlocks = blkDiv( iHeaderSize, iBlockSize );
356 } 361 }
357 aStreams[0]->iSize = iHeaderSize;
358// sio << "Myriad: updateHeader: iHeaderSize=" << iHeaderSize
359// << ", iNewBlocks=" << iNewBlocks << ", curBlocks="
360// << aStreams[0]->aBlocks.getSize() << sio.nl;
361 362
362 MyriadStream sHdr( *this, aStreams[0] ); 363 int iStreamCount;
363 sHdr.write( Myriad_MAGIC_CODE, 4 ); 364 MyriadRead( &iStreamCount, 4 );
365
366 //
367 // Read stream data -- Bootstrap the zero stream
368 //
369 StreamId iStream;
370 MyriadRead( &iStream, 4 );
371 if( iStream != 0 )
372 {
373 throw Bu::MyriadException( Bu::MyriadException::invalidFormat,
374 "The first stream defined must be the header/zero stream.");
375 }
376 iLastUsedIndex = iStream;
377 int32_t iHeaderStreamBytes;
378 MyriadRead( &iHeaderStreamBytes, 4 );
364 379
365 // Version (1) 380 Stream *pHeaderStream = new Stream( *this, iStream, iHeaderStreamBytes );
366 cBuf = 1; 381 hStream.insert( iStream, pHeaderStream );
367 sHdr.write( &cBuf, 1 ); 382 int iHeaderStreamBlocks = blkDiv(iHeaderStreamBytes, iBlockSize );
383 MyriadStream sHeader( *this, pHeaderStream, Read );
368 384
369 // Bits per int 385 // We need to read enough so that we can gurantee that we're within a block
370 cBuf = 32; 386 // that we have read the index to, plus one index.
371 sHdr.write( &cBuf, 1 ); 387 for( int32_t j = 0; j < iHeaderStreamBlocks; j++ )
388 {
389 int32_t iBlockIndex;
390 MyriadRead( &iBlockIndex, 4 );
391 hUnusedBlocks.erase( iBlockIndex );
392 pHeaderStream->aBlocks.append( iBlockIndex );
393 if( rBacking.tell()+4 <= (j+1)*iBlockSize )
394 break;
395 }
372 396
373 // The size of each block 397 // Bootstrap now using the header stream to read the rest of the data.
374 sHdr.write( &iBlockSize, 4 ); 398 sHeader.setPos( rBacking.tell() );
399 while( pHeaderStream->aBlocks.getSize() < iHeaderStreamBlocks )
400 {
401 int32_t iBlockIndex;
402 ReqRead( sHeader, &iBlockIndex, 4 );
403 hUnusedBlocks.erase( iBlockIndex );
404 pHeaderStream->aBlocks.append( iBlockIndex );
405 }
375 406
376 iBuf = aStreams.getSize(); 407 // Ok, now we can read the rest of the header in.
377 // The number of streams 408 for( int j = 1; j < iStreamCount; j++ )
378 sHdr.write( &iBuf, 4 );
379
380 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
381 { 409 {
382 sHdr.write( &(*i)->iId, 4 ); 410 int32_t iStreamBytes;
383 sHdr.write( &(*i)->iSize, 4 ); 411 ReqRead( sHeader, &iStream, 4 );
384 int iUsedBlocks = blkDiv( (*i)->iSize, iBlockSize ); 412 ReqRead( sHeader, &iStreamBytes, 4 );
385// for( BlockArray::iterator j = (*i)->aBlocks.begin(); j; j++ ) 413 Stream *pStream = new Stream( *this, iStream, iStreamBytes );
386 for( int j = 0; j < iUsedBlocks; j++ ) 414 int32_t iBlocks = blkDiv(iStreamBytes, iBlockSize );
415 for( int k = 0; k < iBlocks; k++ )
387 { 416 {
388 sHdr.write( &(*i)->aBlocks[j], 4 ); 417 int32_t iBlockIndex;
418 ReqRead( sHeader, &iBlockIndex, 4 );
419 hUnusedBlocks.erase( iBlockIndex );
420 pStream->aBlocks.append( iBlockIndex );
389 } 421 }
422 hStream.insert( iStream, pStream );
423 if( iLastUsedIndex < iStream )
424 iLastUsedIndex = iStream;
390 } 425 }
426
427 lFreeBlocks = hUnusedBlocks.getKeys();
428 //Bu::println("Free blocks: %1").arg( lFreeBlocks.getSize() );
391 429
392 bHeaderChanged = false; 430 bIsNewStream = false;
393 TRACE("mHeader unlocked..."); 431
432 return true;
394} 433}
395 434
396int Bu::Myriad::createStream( int iPreAllocate ) 435void Bu::Myriad::createMyriad( int32_t iBlockSize, int32_t iPreallocateBlocks )
397{ 436{
398 MutexLocker mLock( mHeader ); 437 if( iBlockSize < 8 )
399 TRACE("mHeader locked."); 438 {
439 throw Bu::MyriadException( Bu::MyriadException::invalidParameter,
440 "iBlockSize cannot be below 8");
441 }
442 if( rBacking.getSize() )
443 {
444 throw Bu::MyriadException( Bu::MyriadException::invalidFormat,
445 "Backing stream contains data, but not a myriad structure.");
446 }
447
448 // Start with the bytes for the file header and initial stream header
449 int iHeaderStreamBytes
450 = 14 // Base header
451 + 8; // Stream header
452
453 // Pick the block count that matches our current estimate for the header
454 // plus one block index.
455 int iHeaderStreamBlocks = blkDiv(iHeaderStreamBytes+4, iBlockSize );
400 456
401 Stream *pStr = new Stream(); 457 //Bu::println("Initial estimate: %1 bytes / %2 cur blocks, %3 computed blocks (%4 target bytes).").arg( iHeaderStreamBytes+(iHeaderStreamBlocks*4) ).arg( iHeaderStreamBlocks ).arg( blkDiv((iHeaderStreamBytes+(iHeaderStreamBlocks*4)), iBlockSize) ).arg( iHeaderStreamBlocks*iBlockSize );
402 pStr->iId = aStreams.last()->iId+1; 458 while( iHeaderStreamBytes+(iHeaderStreamBlocks*4)
403 //sio << "Myriad: New stream id=" << pStr->iId << ", iPreAllocate=" 459 > iHeaderStreamBlocks*iBlockSize )
404 // << iPreAllocate << sio.nl; 460 {
405 pStr->iSize = 0; 461 iHeaderStreamBlocks = blkDiv((iHeaderStreamBytes+((iHeaderStreamBlocks+1)*4)), iBlockSize);
406 aStreams.append( pStr ); 462 if( iHeaderStreamBlocks > 100 )
463 break;
464 //Bu::println(" Adjustment: %1 bytes / %2 cur blocks, %3 computed blocks (%4 target bytes).").arg( iHeaderStreamBytes+(iHeaderStreamBlocks*4) ).arg( iHeaderStreamBlocks ).arg( blkDiv((iHeaderStreamBytes+(iHeaderStreamBlocks*4)), iBlockSize) ).arg( iHeaderStreamBlocks*iBlockSize );
465 }
407 466
408 for( int j = 0; j < iPreAllocate; j++ ) 467 if( iPreallocateBlocks < iHeaderStreamBlocks )
409 { 468 {
410 int iFreeBlock = findEmptyBlock(); 469 iPreallocateBlocks = iHeaderStreamBlocks;
411// sio << "Myriad: Adding block " << iFreeBlock << sio.nl;
412 pStr->aBlocks.append( iFreeBlock );
413// bsBlockUsed.setBit( iFreeBlock );
414 iUsed++;
415 } 470 }
471 rBacking.setSize( iBlockSize*iPreallocateBlocks );
416 472
417 bHeaderChanged = true; 473 //
474 // Write Myriad header
475 //
476 uint8_t uVer = 1;
477 uint8_t uBpi = 32;
478 int32_t iStreamCount = 1;
479 rBacking.setPos( 0 );
480 rBacking.write( Myriad_MAGIC_CODE, 4 );
481 rBacking.write( &uVer, 1 );
482 rBacking.write( &uBpi, 1 );
483 rBacking.write( &iBlockSize, 4 );
484 rBacking.write( &iStreamCount, 4 );
418 485
419 TRACE("mHeader unlocked..."); 486 Stream *pHeadStream = new Stream( *this, 0, Bu::Myriad::ReadWrite );
420 return pStr->iId; 487 //
421} 488 // Write stream header
489 //
490 uint32_t uStreamId = 0;
491 uint32_t uStreamSize = iHeaderStreamBytes+iHeaderStreamBlocks*4;
492 rBacking.write( &uStreamId, 4 );
493 rBacking.write( &uStreamSize, 4 );
494 for( int iBlockIndex = 0; iBlockIndex < iHeaderStreamBlocks; iBlockIndex++ )
495 {
496 rBacking.write( &iBlockIndex, 4 );
497 pHeadStream->aBlocks.append( iBlockIndex );
498 }
499 rBacking.flush();
422 500
423int Bu::Myriad::createStreamWithId( int iId, int iPreAllocate ) 501 hStream.insert( pHeadStream->iStream, pHeadStream );
424{
425 MutexLocker mLock( mHeader );
426 TRACE("mHeader locked.");
427 502
428 try 503 for( int32_t j = iHeaderStreamBlocks; j < iPreallocateBlocks; j++ )
429 { 504 {
430 findStream( iId ); 505 lFreeBlocks.append( j );
431 TRACE("mHeader unlocked...");
432 throw MyriadException( MyriadException::streamExists,
433 "There is already a stream with the given id.");
434 } 506 }
435 catch( MyriadException &e ) 507 iLastUsedIndex = 0;
508 iBlockCount = iPreallocateBlocks;
509}
510
511void Bu::Myriad::writeHeader()
512{
513 Bu::MutexLocker l( mAccess );
514 if( !rBacking.isWritable() )
515 return;
516 //Bu::println("Writing stream breakdown:");
517 Bu::MemBuf mbHeader;
436 { 518 {
437 Stream *pStr = new Stream(); 519 Bu::MutexLocker l2( mhStream );
438 pStr->iId = iId; 520
439 //sio << "Myriad: New stream id=" << pStr->iId << ", iPreAllocate=" 521 int32_t iHdrStreamSize = __calcHeaderSize();
440 // << iPreAllocate << sio.nl; 522 // Maybe just do stream surgery here.
441 pStr->iSize = 0;
442 if( aStreams.last()->iId < iId )
443 {
444 aStreams.append( pStr );
445 }
446 else
447 { 523 {
448 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 524 Stream *psHeader = hStream.get( 0 );
525 Bu::MutexLocker l2( psHeader->mAccess );
526 int iNewBlocks = Bu::blkDiv( iHdrStreamSize, iBlockSize );
527 if( iHdrStreamSize < psHeader->iSize )
449 { 528 {
450 if( (*i)->iId > iId ) 529 while( psHeader->aBlocks.getSize() > iNewBlocks )
451 { 530 {
452 aStreams.insert( i, pStr ); 531 __releaseBlock( psHeader->aBlocks.last(), false );
453 break; 532 psHeader->aBlocks.eraseLast();
454 } 533 }
455 } 534 }
535 else if( iHdrStreamSize > psHeader->iSize )
536 {
537 while( psHeader->aBlocks.getSize() < iNewBlocks )
538 {
539 psHeader->aBlocks.append( __allocateBlock() );
540 }
541 }
542 psHeader->iSize = iHdrStreamSize;
456 } 543 }
457 544
458 for( int j = 0; j < iPreAllocate; j++ ) 545 //Bu::println("Computed header size: %1 bytes. Ver=%2, Bpi=%3, BlockSize=%4").arg( iHdrStreamSize ).arg( 1 ).arg( 32 ).arg( iBlockSize );
546
547 uint8_t uVer = 1;
548 uint8_t uBpi = 32;
549 int32_t iStreamCount = hStream.getSize();
550
551 mbHeader.write( Myriad_MAGIC_CODE, 4 );
552 mbHeader.write( &uVer, 1 );
553 mbHeader.write( &uBpi, 1 );
554 mbHeader.write( &iBlockSize, 4 );
555 mbHeader.write( &iStreamCount, 4 );
556 StreamHash::KeyList lStreamId = hStream.getKeys();
557 lStreamId.sort();
558 if( lStreamId.first() != 0 )
559 {
560 throw Bu::MyriadException( Bu::MyriadException::invalidFormat,
561 "There doesn't appear to be a zero (header) stream.");
562 }
563 for( StreamHash::KeyList::iterator i = lStreamId.begin(); i; i++ )
459 { 564 {
460 int iFreeBlock = findEmptyBlock(); 565 uint32_t uStreamId = *i;
461 // sio << "Myriad: Adding block " << iFreeBlock << sio.nl; 566 Stream *pStream = hStream.get( uStreamId );
462 pStr->aBlocks.append( iFreeBlock ); 567 uint32_t uStreamSize = pStream->getSize();
463// bsBlockUsed.setBit( iFreeBlock ); 568 mbHeader.write( &uStreamId, 4 );
464 iUsed++; 569 mbHeader.write( &uStreamSize, 4 );
570 int32_t iBlocks = Bu::blkDiv( uStreamSize, (uint32_t)iBlockSize );
571 Bu::Array<int32_t> aBlocks = pStream->getBlockList();
572
573 //Bu::println(" Stream %1 is %2 bytes %3 blocks (%4 blocks computed)").arg( *i ).arg( uStreamSize ).arg( aBlocks.getSize() ).arg( Bu::blkDiv( (int)uStreamSize, (int)iBlockSize ) );
574
575// for( Bu::Array<int32_t>::iterator i = aBlocks.begin(); i; i++ )
576 for( int j = 0; j < iBlocks; j++ )
577 {
578 mbHeader.write( &aBlocks[j], 4 );
579 }
465 } 580 }
466 581
467 bHeaderChanged = true;
468 582
469 TRACE("mHeader unlocked...");
470 return pStr->iId;
471 } 583 }
472 TRACE("mHeader unlocked...");
473}
474 584
475int Bu::Myriad::findEmptyBlock() 585 Bu::MyriadStream sHeader( *this, hStream.get( 0 ), Bu::Myriad::Write );
476{ 586 sHeader.write( mbHeader.getString() );
477 bHeaderChanged = true; 587 bStructureChanged = false;
478
479 if( lFreeBlocks.isEmpty() )
480 {
481 sStore.setSize( (iBlocks+1)*(Bu::size)iBlockSize );
482 return iBlocks++;
483 }
484 else
485 {
486 return lFreeBlocks.dequeue();
487 }
488} 588}
489 589
490void Bu::Myriad::deleteStream( int iId ) 590int32_t Bu::Myriad::__calcHeaderSize()
491{ 591{
492 MutexLocker mLock( mHeader ); 592 int32_t iHdrSize = 4+1+1+4+4;
493 TRACE("mHeader locked.");
494 593
495 if( iId < 0 ) 594 StreamHash::KeyList lStreamId = hStream.getKeys();
595 lStreamId.sort();
596 if( lStreamId.first() != 0 )
496 { 597 {
497 TRACE("mHeader unlocked..."); 598 throw Bu::MyriadException( Bu::MyriadException::invalidFormat,
498 throw MyriadException( MyriadException::invalidStreamId, 599 "There doesn't appear to be a zero (header) stream.");
499 "Invalid stream id.");
500 } 600 }
501 if( iId == 0 ) 601 for( StreamHash::KeyList::iterator i = lStreamId.begin(); i; i++ )
502 { 602 {
503 TRACE("mHeader unlocked..."); 603 iHdrSize += 4+4;
504 throw MyriadException( MyriadException::protectedStream, 604 int32_t iStreamSize = hStream.get( *i )->getSize();
505 "You cannot delete stream zero, it is protected."); 605 if( (*i) != 0 )
506 }
507 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
508 {
509 if( (*i)->iId == iId )
510 { 606 {
511 Stream *pStream = *i; 607 iHdrSize += Bu::blkDiv( iStreamSize, iBlockSize )*4;
512 for( BlockArray::iterator j = pStream->aBlocks.begin(); j; j++ )
513 {
514 lFreeBlocks.append( *j );
515// bsBlockUsed.setBit( *j, false );
516 iUsed--;
517 }
518 aStreams.erase( i );
519 bHeaderChanged = true;
520 delete pStream;
521 TRACE("mHeader unlocked...");
522 return;
523 } 608 }
524 } 609 }
525 TRACE("mHeader unlocked...");
526}
527 610
528Bu::Array<int> Bu::Myriad::getStreamIds() 611 //Bu::println("HeaderCalc:");
529{ 612 //Bu::println(" Base (no header stream): %1").arg( iHdrSize );
530 MutexLocker mLock( mHeader ); 613 int32_t iNewSize = iHdrSize;
531 TRACE("mHeader locked."); 614 int32_t iOldSize;
532 615
533 Bu::Array<int> aRet( aStreams.getSize() ); 616 do {
534 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 617 iOldSize = iNewSize;
535 { 618 iNewSize = iHdrSize + Bu::blkDiv(iNewSize, iBlockSize)*4;
536 aRet.append( (*i)->iId ); 619 //Bu::println(" Recomp: %1").arg( iNewSize );
537 } 620 } while( iOldSize != iNewSize );
538 621
539 TRACE("mHeader unlocked..."); 622 return iNewSize;
540 return aRet;
541} 623}
542 624
543int Bu::Myriad::getStreamSize( int iId ) 625int32_t Bu::Myriad::allocateBlock()
544{ 626{
545 MutexLocker mLock( mHeader ); 627 Bu::MutexLocker l( mAccess );
546 TRACE("mHeader locked."); 628 return __allocateBlock();
547
548 TRACE("mHeader unlocked...");
549 return findStream( iId )->iSize;
550} 629}
551 630
552bool Bu::Myriad::hasStream( int iId ) 631int32_t Bu::Myriad::__allocateBlock()
553{ 632{
554 MutexLocker mLock( mHeader ); 633 bStructureChanged = true;
555 TRACE("mHeader locked."); 634 if( lFreeBlocks.isEmpty() )
556
557 try
558 { 635 {
559 findStream( iId ); 636 // Increase the size of the backing stream
560 TRACE("mHeader unlocked..."); 637 int32_t iIndex = iBlockCount++;
561 return true; 638 rBacking.setSize( iBlockCount*iBlockSize );
562 }catch(...) 639 return iIndex;
640 }
641 else
563 { 642 {
564 TRACE("mHeader unlocked..."); 643 // Provide an existing free block.
565 return false; 644 return lFreeBlocks.peekPop();
566 } 645 }
567} 646}
568 647
569Bu::MyriadStream Bu::Myriad::openStream( int iId ) 648void Bu::Myriad::releaseBlock( int32_t iBlockId, bool bBlank )
570{ 649{
571 MutexLocker mLock( mHeader ); 650 Bu::MutexLocker l( mAccess );
572 TRACE("mHeader locked."); 651 __releaseBlock( iBlockId, bBlank );
573
574 TRACE("mHeader unlocked...");
575 //sio << "Myriad: Request to open stream: " << iId << sio.nl;
576 return MyriadStream( *this, findStream( iId ) );
577} 652}
578 653
579int Bu::Myriad::getNumStreams() 654void Bu::Myriad::__releaseBlock( int32_t iBlockId, bool bBlank )
580{ 655{
581 MutexLocker mLock( mHeader ); 656 bStructureChanged = true;
582 TRACE("mHeader locked."); 657 lFreeBlocks.append( iBlockId );
583 658 if( bBlank )
584 TRACE("mHeader unlocked..."); 659 {
585 return aStreams.getSize(); 660 blankBlock( iBlockId );
661 }
586} 662}
587 663
588int Bu::Myriad::getBlockSize() 664void Bu::Myriad::blankBlock( int32_t iBlockId )
589{ 665{
590 return iBlockSize; 666 Bu::MutexLocker l( mBacking );
667 rBacking.setPos( iBlockId*iBlockSize );
668 int32_t iChunk = std::min( iBlockSize, 4096 );
669 uint8_t *pChunk = new uint8_t[iChunk];
670 memset( pChunk, 0, iChunk );
671 int iLeft = iBlockSize;
672 while( iLeft > 0 )
673 {
674 int32_t iWrite = rBacking.write( pChunk, std::min( iChunk, iLeft ) );
675 iLeft -= iWrite;
676 }
677 delete[] pChunk;
591} 678}
592 679
593int Bu::Myriad::getNumBlocks() 680void Bu::Myriad::openStream( StreamId id )
594{ 681{
595 return iBlocks; 682 Bu::MutexLocker l( mhStream );
683 hStream.get( id )->open();
596} 684}
597 685
598int Bu::Myriad::getNumUsedBlocks() 686void Bu::Myriad::closeStream( StreamId id )
599{ 687{
600 return iUsed; 688 Bu::MutexLocker l( mhStream );
689 hStream.get( id )->close();
601} 690}
602 691
603Bu::size Bu::Myriad::getTotalUsedBytes() 692int32_t Bu::Myriad::blockRead( int32_t iBlock, int32_t iStart,
693 void *pTarget, int32_t iSize )
604{ 694{
605 MutexLocker mLock( mHeader ); 695 int32_t iUpperSize = iBlockSize - (iStart%iBlockSize);
606 TRACE("mHeader locked."); 696/* Bu::println("Max read within block: %1 vs %2 (start=%3, blocksize=%4)")
697 .arg( iUpperSize ).arg( iSize )
698 .arg( iStart ).arg( iBlockSize );
699*/
700 int32_t iAmnt = std::min( iSize, iUpperSize );
701 Bu::MutexLocker l( mBacking );
702 rBacking.setPos( iBlockSize*iBlock + iStart );
607 703
608 Bu::size iTotalSize = 0; 704 return rBacking.read( pTarget, iAmnt );
609 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
610 {
611 iTotalSize += (*i)->iSize;
612 }
613 TRACE("mHeader unlocked...");
614 return iTotalSize;
615} 705}
616 706
617Bu::size Bu::Myriad::getTotalUnusedBytes() 707int32_t Bu::Myriad::blockWrite( int32_t iBlock, int32_t iStart,
708 const void *pTarget, int32_t iSize )
618{ 709{
619 MutexLocker mLock( mHeader ); 710 int32_t iUpperSize = iBlockSize - (iStart%iBlockSize);
620 TRACE("mHeader locked."); 711/* Bu::println("Max write within block: %1 vs %2 (start=%3, blocksize=%4)")
712 .arg( iUpperSize ).arg( iSize )
713 .arg( iStart ).arg( iBlockSize );
714*/
715 int32_t iAmnt = std::min( iSize, iUpperSize );
716 Bu::MutexLocker l( mBacking );
717 rBacking.setPos( iBlock*iBlockSize + iStart );
621 718
622 Bu::size iTotalSize = (iBlocks-iUsed)*iBlockSize; 719 return rBacking.write( pTarget, iAmnt );
623 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
624 {
625 iTotalSize += iBlockSize - ((Bu::size)(*i)->iSize%iBlockSize);
626 }
627 TRACE("mHeader unlocked...");
628 return iTotalSize;
629} 720}
630 721
631Bu::size Bu::Myriad::getTotalUnusedBytes( int iFakeBlockSize ) 722/////////
632{ 723// Bu::Myriad::Stream
633 MutexLocker mLock( mHeader ); 724//
634 TRACE("mHeader locked.");
635 725
636 Bu::size iTotalSize = (iBlocks-iUsed)*iFakeBlockSize; 726Bu::Myriad::Stream::Stream( Bu::Myriad &rParent, Bu::Myriad::StreamId iStream,
637 for( StreamArray::iterator i = aStreams.begin(); i; i++ ) 727 int32_t iSize ) :
638 { 728 rParent( rParent ),
639 iTotalSize += iFakeBlockSize - ((*i)->iSize%iFakeBlockSize); 729 iStream( iStream ),
640 } 730 iSize( iSize ),
641 TRACE("mHeader unlocked..."); 731 iOpenCount( 0 )
642 return iTotalSize; 732{
643} 733}
644 734
645Bu::Myriad::Stream *Bu::Myriad::findStream( int iId ) 735Bu::Myriad::Stream::~Stream()
646{ 736{
647 for( StreamArray::iterator i = aStreams.begin(); i; i++ )
648 {
649 if( (*i)->iId == iId )
650 return *i;
651 }
652
653 throw MyriadException( MyriadException::noSuchStream,
654 "The requested stream doesn't exist and cannot be opened." );
655
656 return NULL;
657} 737}
658 738
659Bu::Myriad::Block *Bu::Myriad::getBlock( int iBlock ) 739int32_t Bu::Myriad::Stream::getSize() const
660{ 740{
661// sio << "Myriad: Reading block " << iBlock << ", bytes " 741 Bu::MutexLocker l( mAccess );
662// << iBlockSize*iBlock << "-" << iBlockSize*(iBlock+1) << sio.nl; 742 return iSize;
663 Block *pBlock = new Block; 743}
664 pBlock->pData = new char[iBlockSize];
665 sStore.setPos( iBlockSize * (Bu::size)iBlock );
666 sStore.read( pBlock->pData, iBlockSize );
667 pBlock->bChanged = false;
668 pBlock->iBlockIndex = iBlock;
669
670 mActiveBlocks.lock();
671 TRACE("mHeader locked.");
672 hActiveBlocks.insert( iBlock, pBlock );
673 TRACE("mHeader unlocked...");
674 mActiveBlocks.unlock();
675 744
676 return pBlock; 745int32_t Bu::Myriad::Stream::getBlockSize() const
746{
747 Bu::MutexLocker l( mAccess );
748 return rParent.iBlockSize;
677} 749}
678 750
679void Bu::Myriad::releaseBlock( Bu::Myriad::Block *pBlock ) 751Bu::Myriad::StreamId Bu::Myriad::Stream::getStreamId() const
680{ 752{
681 if( pBlock == NULL ) 753 return iStream;
682 return; 754}
683// sio << "Myriad: Releasing block " << pBlock->iBlockIndex << sio.nl;
684 syncBlock( pBlock );
685 mActiveBlocks.lock();
686 TRACE("mHeader locked.");
687 hActiveBlocks.erase( pBlock->iBlockIndex );
688 TRACE("mHeader unlocked...");
689 mActiveBlocks.unlock();
690 755
691 delete[] pBlock->pData; 756int32_t Bu::Myriad::Stream::getOpenCount() const
692 delete pBlock; 757{
758 Bu::MutexLocker l( mAccess );
759 return iOpenCount;
693} 760}
694 761
695void Bu::Myriad::syncBlock( Block *pBlock ) 762void Bu::Myriad::Stream::setSize( int32_t iNewSize )
696{ 763{
697 if( pBlock->bChanged ) 764 // Two possible modes, shrink or grow.
765 Bu::MutexLocker l( mAccess );
766 int iNewBlocks = Bu::blkDiv( iNewSize, rParent.iBlockSize );
767 if( iNewSize < iSize )
698 { 768 {
699// sio << "Myriad: - Block changed, writing back to stream." << sio.nl; 769 // Shrink it
700 sStore.setPos( iBlockSize * (Bu::size)pBlock->iBlockIndex ); 770 while( aBlocks.getSize() > iNewBlocks )
701 sStore.write( pBlock->pData, iBlockSize ); 771 {
702 pBlock->bChanged = false; 772 rParent.releaseBlock( aBlocks.last(), false );
773 aBlocks.eraseLast();
774 }
775 iSize = iNewSize;
776 }
777 else if( iNewSize > iSize )
778 {
779 // Grow it
780 while( aBlocks.getSize() < iNewBlocks )
781 {
782 aBlocks.append( rParent.allocateBlock() );
783 }
784 iSize = iNewSize;
703 } 785 }
704} 786}
705 787
706int Bu::Myriad::streamAddBlock( Stream *pStream ) 788int32_t Bu::Myriad::Stream::read( int32_t iStart, void *pTarget,
789 int32_t iSize )
707{ 790{
708 MutexLocker mLock( mHeader ); 791 int32_t iRead = 0;
709 TRACE("mHeader locked."); 792 Bu::MutexLocker l( mAccess );
710 793
711 int iBlock = findEmptyBlock(); 794 if( iStart >= this->iSize )
712 pStream->aBlocks.append( iBlock ); 795 return 0;
713// bsBlockUsed.setBit( iBlock );
714// bHeaderChanged = true;
715 iUsed++;
716 TRACE("mHeader unlocked...");
717 return iBlock;
718}
719
720void Bu::Myriad::setStreamSize( Stream *pStream, long iSize )
721{
722 MutexLocker mLock( mHeader );
723 TRACE("mHeader locked.");
724 796
725 if( pStream->iSize == iSize ) 797 if( iStart+iSize >= this->iSize )
726 { 798 {
727 TRACE("mHeader unlocked..."); 799 iSize = this->iSize-iStart;
728 return;
729 } 800 }
730 else if( pStream->iSize > iSize ) 801
802 while( iSize > 0 )
731 { 803 {
732 // Shrink 804 int32_t iBlock = aBlocks[iStart/rParent.iBlockSize];
733 TRACE(Bu::String("Shrink stream %1 from %2 to %3").arg(pStream->iId).arg(pStream->iSize).arg(iSize).end() ); 805 int32_t iChunkRead = rParent.blockRead(
734 for( int iNewSize = pStream->aBlocks.getSize()*iBlockSize; 806 iBlock, iStart%rParent.iBlockSize, pTarget, iSize
735 iNewSize-iBlockSize > iSize; iNewSize -= iBlockSize ) 807 );
736 { 808 if( iChunkRead == 0 )
737// if( bsBlockUsed.getBit( pStream->aBlocks.last() ) ) 809 break;
738 iUsed--; 810 iRead += iChunkRead;
739// else 811 iStart += iChunkRead;
740// sio << "Unused block used in stream? " << pStream->aBlocks.last() << sio.nl; 812 reinterpret_cast<ptrdiff_t &>(pTarget) += iChunkRead;
741 lFreeBlocks.enqueue( pStream->aBlocks.last() ); 813 iSize -= iChunkRead;
742// bsBlockUsed.setBit( pStream->aBlocks.last(), false );
743 pStream->aBlocks.eraseLast();
744 }
745 pStream->iSize = iSize;
746 bHeaderChanged = true;
747 } 814 }
748 else 815
816 return iRead;
817}
818
819int32_t Bu::Myriad::Stream::write( int32_t iStart, const void *pTarget,
820 int32_t iSize )
821{
822 int32_t iWrite = 0;
823 Bu::MutexLocker l( mAccess );
824 while( iSize > 0 )
749 { 825 {
750 // Grow 826 int32_t iBlockIdx = iStart/rParent.iBlockSize;
751 TRACE(Bu::String("Grow stream %1 from %2 to %3").arg(pStream->iId).arg(pStream->iSize).arg(iSize).end() ); 827 while( iBlockIdx >= aBlocks.getSize() )
752 for( int iNewSize = pStream->aBlocks.getSize()*iBlockSize;
753 iNewSize < iSize; iNewSize += iBlockSize )
754 { 828 {
755 //streamAddBlock( pStream ); 829 aBlocks.append( rParent.allocateBlock() );
756 int iBlock = findEmptyBlock();
757 pStream->aBlocks.append( iBlock );
758// bsBlockUsed.setBit( iBlock );
759// bHeaderChanged = true;
760 iUsed++;
761 } 830 }
762 pStream->iSize = iSize; 831 int32_t iBlock = aBlocks[iBlockIdx];
763 bHeaderChanged = true; 832 int32_t iChunkWrite = rParent.blockWrite(
833 iBlock, iStart%rParent.iBlockSize, pTarget, iSize
834 );
835 if( iChunkWrite == 0 )
836 break;
837 iWrite += iChunkWrite;
838 iStart += iChunkWrite;
839 reinterpret_cast<ptrdiff_t &>(pTarget) += iChunkWrite;
840 iSize -= iChunkWrite;
764 } 841 }
765 TRACE("mHeader unlocked..."); 842 if( this->iSize < iStart )
843 this->iSize = iStart;
844
845 return iWrite;
766} 846}
767 847
768void Bu::Myriad::headerChanged() 848Bu::String Bu::Myriad::Stream::getLocation() const
769{ 849{
770 bHeaderChanged = true; 850 Bu::MutexLocker l( mAccess );
851 return Bu::String("%1:stream %2")\
852 .arg( rParent.getLocation() ).arg( iStream );
771} 853}
772 854
773bool Bu::Myriad::isMyriad( Bu::Stream &sStore ) 855Bu::Array<int32_t> Bu::Myriad::Stream::getBlockList() const
774{ 856{
775 uint8_t uTmp; 857 Bu::MutexLocker l( mAccess );
776 858 return aBlocks.clone();
777 return isMyriad( sStore, uTmp );
778} 859}
779 860
780bool Bu::Myriad::isMyriad( Bu::Stream &sStore, uint8_t &uTmp ) 861void Bu::Myriad::Stream::open()
781{ 862{
782 sStore.setPos( 0 ); 863 Bu::MutexLocker l( mAccess );
783 864 iOpenCount++;
784 unsigned char buf[4];
785 if( sStore.read( buf, 4 ) < 4 )
786 throw MyriadException( MyriadException::emptyStream,
787 "Input stream appears to be empty.");
788 sStore.read( &uTmp, 1 );
789 sStore.setPos( 0 );
790 if( memcmp( buf, Myriad_MAGIC_CODE, 4 ) )
791 {
792 return false;
793 }
794 return true;
795} 865}
796 866
797const Bu::BitString Bu::Myriad::getBlocksUsed() const 867bool Bu::Myriad::Stream::close()
798{ 868{
799 Bu::BitString bs( iBlocks, false ); 869 Bu::MutexLocker l( mAccess );
800 for( int j = 0; j < iBlocks; j++ ) 870 return (bool)(--iOpenCount);
801 bs.setBit( j );
802 for( IndexList::const_iterator i = lFreeBlocks.begin(); i; i++ )
803 bs.setBit( *i, false );
804 return bs;
805} 871}
806 872
diff --git a/src/stable/myriad.h b/src/stable/myriad.h
index 14467a4..5accd1e 100644
--- a/src/stable/myriad.h
+++ b/src/stable/myriad.h
@@ -1,24 +1,16 @@
1/*
2 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_MYRIAD_H 1#ifndef BU_MYRIAD_H
9#define BU_MYRIAD_H 2#define BU_MYRIAD_H
10 3
11#include <stdint.h> 4#include "bu/stream.h"
12#include "bu/bitstring.h"
13#include "bu/exceptionbase.h" 5#include "bu/exceptionbase.h"
6#include "bu/mutex.h"
14#include "bu/array.h" 7#include "bu/array.h"
15#include "bu/hash.h" 8#include "bu/hash.h"
16#include "bu/mutex.h" 9
17#include "bu/extratypes.h" 10#include "bu/bitstring.h"
18 11
19namespace Bu 12namespace Bu
20{ 13{
21 class Stream;
22 class MyriadStream; 14 class MyriadStream;
23 15
24 subExceptionDeclBegin( MyriadException ) 16 subExceptionDeclBegin( MyriadException )
@@ -31,206 +23,229 @@ namespace Bu
31 noSuchStream, 23 noSuchStream,
32 streamExists, 24 streamExists,
33 invalidStreamId, 25 invalidStreamId,
34 protectedStream 26 protectedStream,
27 invalidParameter,
28 invalidBackingStream,
29 badMode,
30 streamOpen,
35 }; 31 };
36 subExceptionDeclEnd(); 32 subExceptionDeclEnd();
37 33
38 /** 34 /**
39 * Myriad block-allocated stream multiplexing system. This is a system for 35 * Myriad Stream Multiplexer. This is a system that allows you to store
40 * creating streams that contain other streams in a flexible and lightweight 36 * many streams within a single backing stream. This is great for databases,
41 * manner. Basically, you can create a file (or any other stream) that can 37 * caching, etc. It's fairly lightweight, and allows all streams to grow
42 * store any number of flexible, growing streams. The streams within the 38 * dynamically using a block-allocation scheme. This is used extensively
43 * Myriad stream are automatically numbered, not named. This works more 39 * by the caching system and MyriadFs as well as other systems within
44 * or less like a filesystem, but without the extra layer for managing 40 * libbu++.
45 * file and directory links. This would actually be very easy to add
46 * on top of Myriad, but is not required.
47 *
48 * Header format is as follows:
49 *
50 * MMMMvBssssSSSS*
51 * M = Magic number (0AD3FA84)
52 * v = version number
53 * B = Bits per int
54 * s = Blocksize in bytes
55 * S = Number of Streams
56 *
57 * The * represents the Stream headers, one per stream, as follows:
58 * IIIIssss$
59 * I = Id number of the stream
60 * s = size of stream in bytes
61 *
62 * The $ represents the Block headers, one per used block, as follows:
63 * IIII
64 * I = Index of the block
65 *
66 * The stream/block data is interleaved in the header, so all blocks stored
67 * with one stream are together. The block headers are in order, and the
68 * data in them is required to be "solid" you cannot fill partial blocks
69 * mid-way through a stream.
70 *
71 * The initial block starts with the nids header, and is both the zero block
72 * and the zero stream. For now, the minimum block size is the size needed
73 * to store the base header, the zero stream header, and the first two
74 * blocks of the zero stream, so 30 bytes. Since it's reccomended to use
75 * a size that will fit evenly into filesystem blocks, then a size of 32 is
76 * probably the smallest reccomended size because all powers of two equal
77 * to or greater than 32 are evenly divisible by 32.
78 *
79 * I have had a thought that if the block size were smaller than 42 bytes
80 * the header would consume the first N blocks where N * block size is
81 * enough space to house the initial header, the first stream header, and
82 * the first N block headers. This, of course, causes you to hit an
83 * infinite header if the block size is small enough.
84 */ 41 */
85 class Myriad 42 class Myriad
86 { 43 {
87 friend class MyriadStream; 44 public:
45 typedef int32_t StreamId;
46 typedef Bu::Array<StreamId> StreamIdArray;
47 typedef Bu::List<StreamId> StreamIdList;
48 enum Mode : int32_t {
49 None = 0x00,
50
51 // Flags
52 Read = 0x01, ///< Open file for reading
53 Write = 0x02, ///< Open file for writing
54 Create = 0x04, ///< Create file if it doesn't exist
55 Truncate = 0x08, ///< Truncate file if it does exist
56 Append = 0x10, ///< Start writing at end of file
57 //NonBlock = 0x20, ///< Open file in non-blocking mode
58 Exclusive = 0x40, ///< Create file, if it exists then fail
59
60 // Helpful mixes
61 ReadWrite = 0x03, ///< Open for reading and writing
62 WriteNew = 0x0E ///< Create a file (or truncate) for writing.
63 /// Same as Write|Create|Truncate
64 };
65
88 public: 66 public:
89 /** 67 /**
90 * Create a Myriad object that uses the given stream to store data. 68 * Open existing Myriad container, or initialize a new one if the
91 * This stream must be random access. The block size and preallocate 69 * backing stream is empty. If other data is already in the provided
92 * values passed in are values that will be used if the given stream 70 * backing stream an error is thrown.
93 * is empty. In that case the stream will be "formatted" for myriad 71 *
94 * with the specified block size. If there is already a viable Myriad 72 * Myriad format V0
95 * format present in the stream, then the blocksize and preallocate 73 * 0 - 3: Myriad_MAGIC_CODE (0ad3fa84)
96 * values will be ignored and the values from the stream will be used 74 * 4 - 4: Version Id (1)
97 * instead. If the stream doesn't appear to be Myriad formatted an 75 * 5 - 5: Bits per integer (32)
98 * exception will be thrown. 76 * 6 - 9: Block size in bytes.
77 * 10 - 13: Number of streams.
78 * 14 - ...: Stream Data
79 *
80 * Stream Data:
81 * 0 - 3: Stream Id
82 * 4 - 7: Size of stream in bytes
83 * 8 - ...: List of blocks in stream (4 bytes per block
99 */ 84 */
100 Myriad( Bu::Stream &sStore, int iBlockSize=512, int iPreallocate=8 ); 85 Myriad( Bu::Stream &rBacking, int32_t iBlockSize=-1,
86 int32_t iPreallocateBlocks=-1 );
101 virtual ~Myriad(); 87 virtual ~Myriad();
102 88
103 /** 89 /**
104 * Destroy whatever data may be in the base stream and create a new 90 * Creates a new stream open in the specified eMode and, optionally,
105 * Myriad system there with the given blocksize. Use this with care, 91 * preallocates the specificed amount of space. The stream is zero
106 * it will destroy anything that was already in the stream, and 92 * bytes even if space is preallocated. The open stream is returned,
107 * generally, should not ever have to be used. 93 * ready for use. Use this if you don't care what the id is of the
94 * newly created stream.
108 */ 95 */
109 void initialize( int iBlockSize, int iPreAllocate=1 ); 96 MyriadStream create( Mode eMode, int32_t iPreallocateBytes=-1 );
110 97
111 /** 98 /**
112 * Create a new stream within the Myriad system. The ID of the new 99 * Open an existing stream or create a new stream with the specified
113 * stream is returned. 100 * id (iStream) with the specified eMode. This respects the normal file
101 * modes, see Bu::Myriad::Mode for details.
114 */ 102 */
115 int createStream( int iPreAllocate=1 ); 103 MyriadStream open( StreamId iStream, Mode eMode );
116 104
117 /** 105 /**
118 * Create a new stream within the Myriad system with a given id. The 106 * Allocate a new stream but do not open it, just ensure it exists and
119 * id that you provide will be the new id of the stream unless it's 107 * return the id of the newly allocated stream.
120 * already used, in which case an error is thrown. This is primarilly
121 * useful when copying an old Myriad file into a new one.
122 */ 108 */
123 int createStreamWithId( int iId, int iPreAllocate=1 ); 109 StreamId allocate();
124 110
125 /** 111 /**
126 * Delete a stream that's already within the Myriad. 112 * Erase the stream specified by iStream. This only can work when the
113 * stream is not open at the moment.
127 */ 114 */
128 void deleteStream( int iId ); 115 void erase( StreamId iStream );
129 116 void setSize( StreamId iStream, int32_t iNewSize );
117 int32_t getSize( StreamId iStream ) const;
118 bool exists( StreamId iStream ) const;
119 Bu::String getLocation() const;
120 int32_t getBlockSize() const;
121 int32_t getTotalBlocks() const;
122 int32_t getUsedBlocks() const;
123 int32_t getFreeBlocks() const;
124 int32_t getTotalStreams() const;
125 int32_t getTotalUsedBytes() const;
126 int32_t getTotalUnusedBytes( int32_t iAssumeBlockSize=-1 ) const;
127 Bu::BitString buildBlockUseMap() const;
128 StreamIdArray buildBlockMap() const;
129
130 /** 130 /**
131 * Return a new Stream object assosiated with the given stream ID. 131 * Lists all stream ids that you are allowed to open. Technically there
132 * is always a zero stream, but it is used by Myriad for stream/block
133 * accounting. It works like a normal stream but you should not open
134 * it.
132 */ 135 */
133 MyriadStream openStream( int iId ); 136 StreamIdList getStreamList() const;
134
135 Bu::Array<int> getStreamIds();
136 int getStreamSize( int iId );
137 bool hasStream( int iId );
138
139 int getNumStreams();
140 int getBlockSize();
141 int getNumBlocks();
142 int getNumUsedBlocks();
143 Bu::size getTotalUsedBytes();
144 Bu::size getTotalUnusedBytes();
145 Bu::size getTotalUnusedBytes( int iFakeBlockSize );
146 137
147 /** 138 /**
148 * Syncronize the header data, etc. with the storage stream. It's not 139 * Flush all caches to the backing stream, write all structural and
149 * a bad idea to call this periodically. 140 * header changes.
150 */ 141 */
151 void sync(); 142 void sync();
152 143
144 private:
145 bool loadMyriad();
146 void createMyriad( int32_t iBlockSize, int32_t iPreallocateBlocks );
147 void writeHeader();
148 int32_t __calcHeaderSize();
149 int32_t allocateBlock();
150 int32_t __allocateBlock();
151 void releaseBlock( int32_t iBlockId, bool bBlank=true );
152 void __releaseBlock( int32_t iBlockId, bool bBlank=true );
153 void blankBlock( int32_t iBlockId );
154
155 void openStream( StreamId id );
156 void closeStream( StreamId id );
153 /** 157 /**
154 * Read the first few bytes from the given stream and return true/false 158 * Block restricted read, it will not read past the end of the block
155 * depending on weather or not it's a Myriad stream. This will throw 159 * that iStart places it in.
156 * an exception if the stream is empty, or is not random access.
157 */ 160 */
158 static bool isMyriad( Bu::Stream &sStore, uint8_t &uVer ); 161 int32_t blockRead( int32_t iBlock, int32_t iStart,
159 162 void *pTarget, int32_t iSize );
163
160 /** 164 /**
161 * Read the first few bytes from the given stream and return true/false 165 * Block restricted write, it will not write past the end of the block
162 * depending on weather or not it's a Myriad stream. This will throw 166 * that iStart places it in. If this returns a non-zero number it's an
163 * an exception if the stream is empty, or is not random access. 167 * indication that you need to allocate a new block.
164 */ 168 */
165 static bool isMyriad( Bu::Stream &sStore ); 169 int32_t blockWrite( int32_t iBlock, int32_t iStart,
170 const void *pTarget, int32_t iSize );
166 171
167 const Bu::BitString getBlocksUsed() const; 172 public:
168
169 private:
170 /** 173 /**
171 * Initialize this object based on the data already in the assosiated 174 * Bridge/communication/tracking class for individual Myriad streams.
172 * stream. This will be called automatically for you if you forget, 175 * Not for general use, this is used by Myriad and MyriadStream to
173 * but if you want to pre-initialize for some reason, just call this 176 * control access.
174 * once before you actually start doing anything with your Myriad.
175 */ 177 */
176 void initialize();
177
178 enum
179 {
180 blockUnused = 0xFFFFFFFFUL
181 };
182
183 typedef Bu::Array<int> BlockArray;
184 class Stream 178 class Stream
185 { 179 {
186 public: 180 friend Bu::Myriad;
187 int iId; 181 private:
188 int iSize; 182 Stream( Myriad &rParent, StreamId iStream, int32_t iSize );
189 BlockArray aBlocks; 183 virtual ~Stream();
190 };
191 typedef Bu::Array<Stream *> StreamArray;
192 184
193 class Block
194 {
195 public: 185 public:
196 char *pData; 186 int32_t getSize() const;
197 bool bChanged; 187 int32_t getBlockSize() const;
198 int iBlockIndex; 188 StreamId getStreamId() const;
189 int32_t getOpenCount() const;
190
191 void setSize( int32_t iNewSize );
192 int32_t read( int32_t iStart, void *pTarget, int32_t iSize );
193 int32_t write( int32_t iStart, const void *pTarget, int32_t iSize );
194 Bu::String getLocation() const;
195 Bu::Array<int32_t> getBlockList() const;
196
197 /**
198 * Doesn't actually open, just increments the open counter.
199 * If the open counter is non-zero then at least one stream has
200 * a lock on this stream.
201 */
202 void open();
203
204 /**
205 * Doesn't actually close, just decrements the open counter.
206 *@returns true if there are still handles open, false if no
207 * streams have a lock.
208 */
209 bool close();
210
211 private:
212 mutable Bu::Mutex mAccess;
213 Myriad &rParent;
214 StreamId iStream;
215 int32_t iSize;
216 Bu::Array<int32_t> aBlocks;
217 int32_t iOpenCount;
199 }; 218 };
200 219
201 void updateHeader();
202 int findEmptyBlock();
203
204 /**
205 *@todo Change this to use a binary search, it's nicer.
206 */
207 Stream *findStream( int iId );
208
209 Block *getBlock( int iBlock );
210 void releaseBlock( Block *pBlock );
211 void syncBlock( Block *pBlock );
212
213 int streamAddBlock( Stream *pStream );
214 void setStreamSize( Stream *pStream, long iSize );
215
216 void headerChanged();
217
218 private: 220 private:
219 Bu::Stream &sStore; 221 typedef Bu::Hash<StreamId, Stream *> StreamHash;
220 int iBlockSize; 222 typedef Bu::List<int32_t> IndexList;
221 int iBlocks; 223 mutable Bu::Mutex mAccess;
222 int iUsed; 224 mutable Bu::Mutex mBacking;
223 typedef Bu::List<int> IndexList; 225 Bu::Stream &rBacking;
226 int32_t iBlockSize;
227 int32_t iBlockCount;
228 bool bIsNewStream;
229 bool bStructureChanged;
230 mutable Bu::Mutex mhStream;
231 StreamHash hStream;
224 IndexList lFreeBlocks; 232 IndexList lFreeBlocks;
225// Bu::BitString bsBlockUsed; 233 StreamId iLastUsedIndex;
226 StreamArray aStreams;
227 typedef Bu::Hash<int, Block *> BlockHash;
228 BlockHash hActiveBlocks;
229 bool bHeaderChanged;
230
231 Bu::Mutex mHeader;
232 Bu::Mutex mActiveBlocks;
233 }; 234 };
235 constexpr Myriad::Mode operator&( Myriad::Mode a, Myriad::Mode b )
236 {
237 return static_cast<Myriad::Mode>(
238 static_cast<std::underlying_type<Myriad::Mode>::type>(a) &
239 static_cast<std::underlying_type<Myriad::Mode>::type>(b)
240 );
241 }
242 constexpr Myriad::Mode operator|( Myriad::Mode a, Myriad::Mode b )
243 {
244 return static_cast<Myriad::Mode>(
245 static_cast<std::underlying_type<Myriad::Mode>::type>(a) |
246 static_cast<std::underlying_type<Myriad::Mode>::type>(b)
247 );
248 }
234}; 249};
235 250
236#endif 251#endif
diff --git a/src/stable/myriadstream.cpp b/src/stable/myriadstream.cpp
index 50c6924..eaf91a5 100644
--- a/src/stable/myriadstream.cpp
+++ b/src/stable/myriadstream.cpp
@@ -1,248 +1,96 @@
1/*
2 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/myriadstream.h" 1#include "bu/myriadstream.h"
9 2
10#include <string.h> 3#include "bu/mutexlocker.h"
11
12// #define MYRIAD_STREAM_DEBUG 1
13
14#ifdef MYRIAD_STREAM_DEBUG
15#include "bu/sio.h"
16
17using Bu::sio;
18using Bu::Fmt;
19#endif
20#include "bu/sio.h"
21
22#define TRACE( x ) Bu::println("%1:%2: %3: %4 - %5").arg(__FILE__).arg( __LINE__ ).arg(__PRETTY_FUNCTION__).arg(rMyriad.sStore.getLocation()).arg(x)
23 4
24Bu::MyriadStream::MyriadStream( Bu::Myriad &rMyriad, 5Bu::MyriadStream::MyriadStream( Bu::Myriad &rMyriad,
25 Bu::Myriad::Stream *pStream ) : 6 Bu::Myriad::Stream *pStream, Bu::Myriad::Mode eMode ) :
26 rMyriad( rMyriad ), 7 rMyriad( rMyriad ),
27 pStream( pStream ), 8 pStream( pStream ),
28 pCurBlock( NULL ), 9 eMode( eMode ),
29 iPos( 0 ) 10 iPos( 0 )
30{ 11{
31#ifdef MYRIAD_STREAM_DEBUG 12 if( (eMode&Bu::Myriad::ReadWrite) == 0 )
32 sio << "MyriadStream: " << __LINE__ << ": Created, iId=" << pStream->iId << ", iSize=" 13 {
33 << pStream->iSize << sio.nl; 14 throw Bu::MyriadException( Bu::MyriadException::invalidParameter,
34#endif 15 "MyriadStream must be opened Read or Write or both.");
35 //pCurBlock = rMyriad.newBlock(); 16 }
36 //rMyriad.getBlock( uStream, pCurBlock ); 17 Bu::MutexLocker l( mAccess );
37 //uSize = pCurBlock->uBytesUsed; 18 pStream->open();
19
20 if( (eMode&Bu::Myriad::Write) != 0 )
21 {
22 // Writing mode, what other options do we deal with?
23 if( (eMode&Bu::Myriad::Truncate) != 0 )
24 {
25 // Truncate, set size to zero before starting.
26 pStream->setSize( 0 );
27 }
28 else if( (eMode&Bu::Myriad::Append) != 0 )
29 {
30 iPos = pStream->getSize();
31 }
32 }
38} 33}
39 34
40Bu::MyriadStream::~MyriadStream() 35Bu::MyriadStream::~MyriadStream()
41{ 36{
42 if( pCurBlock ) 37 close();
43 rMyriad.releaseBlock( pCurBlock );
44 //rMyriad.updateStreamSize( uStream, uSize );
45 //rMyriad.deleteBlock( pCurBlock );
46} 38}
47 39
48void Bu::MyriadStream::close() 40void Bu::MyriadStream::close()
49{ 41{
50} 42 Bu::MutexLocker l( mAccess );
51 43 if( eMode )
52Bu::size Bu::MyriadStream::read( void *pBuf, Bu::size nBytes )
53{
54#ifdef MYRIAD_STREAM_DEBUG
55 sio << "MyriadStream: read: " << __LINE__ << ": Started, asked to read " << nBytes << "b."
56 << sio.nl;
57#endif
58 if( nBytes > (Bu::size)pStream->iSize-iPos )
59 nBytes = pStream->iSize-iPos;
60 if( nBytes <= 0 )
61 return 0;
62 int iLeft = nBytes;
63#ifdef MYRIAD_STREAM_DEBUG
64 sio << "MyriadStream: read: " << __LINE__ << ": Started, going to read " << nBytes << "b."
65 << sio.nl;
66#endif
67 if( pCurBlock == NULL )
68 { 44 {
69#ifdef MYRIAD_STREAM_DEBUG 45 pStream->close();
70 sio << "MyriadStream: read: " << __LINE__ << ": No block loaded, loading initial block." 46 eMode = Bu::Myriad::None;
71 << sio.nl;
72#endif
73 pCurBlock = rMyriad.getBlock(
74 pStream->aBlocks[iPos/rMyriad.iBlockSize]
75 );
76 }
77 while( iLeft > 0 )
78 {
79 int iCurBlock = pStream->aBlocks[iPos/rMyriad.iBlockSize];
80 if( pCurBlock->iBlockIndex != iCurBlock )
81 {
82#ifdef MYRIAD_STREAM_DEBUG
83 sio << "MyriadStream: read: " << __LINE__ << ": Loading new block " << iCurBlock << "."
84 << sio.nl;
85#endif
86 rMyriad.releaseBlock( pCurBlock );
87 pCurBlock = rMyriad.getBlock( iCurBlock );
88 }
89
90 int iAmnt = Bu::buMin(
91 Bu::buMin(
92 rMyriad.iBlockSize - iPos%rMyriad.iBlockSize,
93 iLeft
94 ),
95 pStream->iSize-iPos
96 );
97#ifdef MYRIAD_STREAM_DEBUG
98 sio << "MyriadStream: read: " << __LINE__ << ": Copying out bytes: "
99 << iPos << "(" << (iPos%rMyriad.iBlockSize) << ")+"
100 << iAmnt
101 << ", " << iLeft << "b left." << sio.nl;
102#endif
103 memcpy(
104 pBuf,
105 pCurBlock->pData+(iPos%rMyriad.iBlockSize),
106 iAmnt
107 );
108 iPos += iAmnt;
109 pBuf = &((char *)pBuf)[iAmnt];
110 iLeft -= iAmnt;
111 } 47 }
112 return nBytes;
113} 48}
114 49
115Bu::size Bu::MyriadStream::write( const void *pBuf, Bu::size nBytes ) 50Bu::size Bu::MyriadStream::read( void *pBuf, size iBytes )
116{ 51{
117 if( nBytes <= 0 ) 52 Bu::MutexLocker l( mAccess );
118 return 0; 53 int32_t iRead = pStream->read( iPos, pBuf, iBytes );
119 54 iPos += iRead;
120#ifdef MYRIAD_STREAM_DEBUG 55 return iRead;
121 sio << "MyriadStream: write: " << __LINE__ << ": Started, asked to write " << nBytes << "b." 56}
122 << sio.nl;
123#endif
124 if( nBytes <= 0 )
125 return 0;
126 int iLeft = nBytes;
127 /*
128 if( pCurBlock == NULL )
129 {
130#ifdef MYRIAD_STREAM_DEBUG
131 sio << "MyriadStream: write: No block loaded, loading initial block."
132 << sio.nl;
133#endif
134 pCurBlock = rMyriad.getBlock(
135 pStream->aBlocks[iPos/rMyriad.iBlockSize]
136 );
137 }*/
138
139 while( iLeft > 0 )
140 {
141 int iCurBlock;
142 if( iPos/rMyriad.iBlockSize < pStream->aBlocks.getSize() )
143 {
144 iCurBlock = pStream->aBlocks[iPos/rMyriad.iBlockSize];
145 }
146 else
147 {
148 iCurBlock = rMyriad.streamAddBlock( pStream );
149#ifdef MYRIAD_STREAM_DEBUG
150 sio << "MyriadStream: write: " << __LINE__ << ": New block allocated and appended: "
151 << iCurBlock << "." << sio.nl;
152
153#endif
154 }
155 if( !pCurBlock || pCurBlock->iBlockIndex != iCurBlock )
156 {
157#ifdef MYRIAD_STREAM_DEBUG
158 sio << "MyriadStream: write: " << __LINE__ << ": Loading new block " << iCurBlock << "."
159 << sio.nl;
160#endif
161 rMyriad.releaseBlock( pCurBlock );
162 pCurBlock = rMyriad.getBlock( iCurBlock );
163 }
164 pCurBlock->bChanged = true;
165
166 // There are two main writing modes when it comes down to it.
167 // Overwrite mode and append mode. Append is what pretty much always
168 // happens when creating a new stream.
169 if( iPos < pStream->iSize )
170 {
171 int iAmnt = Bu::buMin(
172 Bu::buMin(
173 rMyriad.iBlockSize - iPos%rMyriad.iBlockSize,
174 iLeft
175 ),
176 pStream->iSize-iPos
177 );
178#ifdef MYRIAD_STREAM_DEBUG
179 sio << "MyriadStream: write (ovr): " << __LINE__ << ": Copying in bytes: "
180 << (iPos%rMyriad.iBlockSize) << "+"
181 << iAmnt
182 << ", " << iLeft << "b left." << sio.nl;
183#endif
184 memcpy(
185 pCurBlock->pData+(iPos%rMyriad.iBlockSize),
186 pBuf,
187 iAmnt
188 );
189 iPos += iAmnt;
190 pBuf = &((char *)pBuf)[iAmnt];
191 iLeft -= iAmnt;
192 }
193 else
194 {
195 int iAmnt = Bu::buMin(
196 rMyriad.iBlockSize - iPos%rMyriad.iBlockSize,
197 iLeft
198 );
199#ifdef MYRIAD_STREAM_DEBUG
200 sio << "MyriadStream: write (app): " << __LINE__ << ": Copying in bytes: "
201 << (iPos%rMyriad.iBlockSize) << "+"
202 << iAmnt
203 << ", " << iLeft << "b left." << sio.nl;
204#endif
205 memcpy(
206 pCurBlock->pData+(iPos%rMyriad.iBlockSize),
207 pBuf,
208 iAmnt
209 );
210 iPos += iAmnt;
211 TRACE(Bu::String("Stream=%1 - pStream->iSize(%2) += iAmnt(%3)").arg(pStream->iId).arg( pStream->iSize ).arg(iAmnt).end());
212 pStream->iSize += iAmnt;
213 TRACE(Bu::String("Stream=%1 - pStream->iSize = %2").arg(pStream->iId).arg( pStream->iSize ).end());
214 rMyriad.headerChanged();
215 pBuf = &((char *)pBuf)[iAmnt];
216 iLeft -= iAmnt;
217 }
218 }
219 57
220 return nBytes; 58Bu::size Bu::MyriadStream::write( const void *pBuf, size iBytes )
59{
60 Bu::MutexLocker l( mAccess );
61 int32_t iWrite = pStream->write( iPos, pBuf, iBytes );
62 iPos += iWrite;
63 return iWrite;
221} 64}
222 65
223Bu::size Bu::MyriadStream::tell() 66Bu::size Bu::MyriadStream::tell()
224{ 67{
68 Bu::MutexLocker l( mAccess );
225 return iPos; 69 return iPos;
226} 70}
227 71
228void Bu::MyriadStream::seek( Bu::size offset ) 72void Bu::MyriadStream::seek( size offset )
229{ 73{
74 Bu::MutexLocker l( mAccess );
230 iPos += offset; 75 iPos += offset;
231} 76}
232 77
233void Bu::MyriadStream::setPos( Bu::size pos ) 78void Bu::MyriadStream::setPos( size pos )
234{ 79{
80 Bu::MutexLocker l( mAccess );
235 iPos = pos; 81 iPos = pos;
236} 82}
237 83
238void Bu::MyriadStream::setPosEnd( Bu::size pos ) 84void Bu::MyriadStream::setPosEnd( size pos )
239{ 85{
240 iPos = pStream->iSize-pos; 86 Bu::MutexLocker l( mAccess );
87 iPos = pStream->getSize()-pos;
241} 88}
242 89
243bool Bu::MyriadStream::isEos() 90bool Bu::MyriadStream::isEos()
244{ 91{
245 return iPos >= pStream->iSize; 92 Bu::MutexLocker l( mAccess );
93 return iPos == pStream->getSize();
246} 94}
247 95
248bool Bu::MyriadStream::isOpen() 96bool Bu::MyriadStream::isOpen()
@@ -252,6 +100,7 @@ bool Bu::MyriadStream::isOpen()
252 100
253void Bu::MyriadStream::flush() 101void Bu::MyriadStream::flush()
254{ 102{
103 // Does this make sense?
255} 104}
256 105
257bool Bu::MyriadStream::canRead() 106bool Bu::MyriadStream::canRead()
@@ -266,12 +115,14 @@ bool Bu::MyriadStream::canWrite()
266 115
267bool Bu::MyriadStream::isReadable() 116bool Bu::MyriadStream::isReadable()
268{ 117{
269 return true; 118 Bu::MutexLocker l( mAccess );
119 return (eMode&Bu::Myriad::Read) != 0;
270} 120}
271 121
272bool Bu::MyriadStream::isWritable() 122bool Bu::MyriadStream::isWritable()
273{ 123{
274 return true; 124 Bu::MutexLocker l( mAccess );
125 return (eMode&Bu::Myriad::Write) != 0;
275} 126}
276 127
277bool Bu::MyriadStream::isSeekable() 128bool Bu::MyriadStream::isSeekable()
@@ -286,29 +137,38 @@ bool Bu::MyriadStream::isBlocking()
286 137
287void Bu::MyriadStream::setBlocking( bool /*bBlocking*/ ) 138void Bu::MyriadStream::setBlocking( bool /*bBlocking*/ )
288{ 139{
140 // Dunno what this would even mean here.
289} 141}
290 142
291void Bu::MyriadStream::setSize( Bu::size iSize ) 143void Bu::MyriadStream::setSize( size iSize )
292{ 144{
293 if( iSize < 0 ) 145 Bu::MutexLocker l( mAccess );
294 iSize = 0; 146 pStream->setSize( iSize );
295 rMyriad.setStreamSize( pStream, iSize );
296 if( iPos > iSize ) 147 if( iPos > iSize )
297 iPos = iSize; 148 iPos = iSize;
298} 149}
299 150
300Bu::size Bu::MyriadStream::getSize() const 151Bu::size Bu::MyriadStream::getSize() const
301{ 152{
302 return pStream->iSize; 153 Bu::MutexLocker l( mAccess );
154 return pStream->getSize();
303} 155}
304 156
305Bu::size Bu::MyriadStream::getBlockSize() const 157Bu::size Bu::MyriadStream::getBlockSize() const
306{ 158{
307 return rMyriad.getBlockSize(); 159 Bu::MutexLocker l( mAccess );
160 return pStream->getBlockSize();
308} 161}
309 162
310Bu::String Bu::MyriadStream::getLocation() const 163Bu::String Bu::MyriadStream::getLocation() const
311{ 164{
312 return Bu::String("%1").arg( pStream->iId ); 165 Bu::MutexLocker l( mAccess );
166 return pStream->getLocation();
167}
168
169Bu::Myriad::StreamId Bu::MyriadStream::getId() const
170{
171 Bu::MutexLocker l( mAccess );
172 return pStream->getStreamId();
313} 173}
314 174
diff --git a/src/stable/myriadstream.h b/src/stable/myriadstream.h
index a94a9a2..27a15d5 100644
--- a/src/stable/myriadstream.h
+++ b/src/stable/myriadstream.h
@@ -1,38 +1,30 @@
1/*
2 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_MYRIAD_STREAM_H 1#ifndef BU_MYRIAD_STREAM_H
9#define BU_MYRIAD_STREAM_H 2#define BU_MYRIAD_STREAM_H
10 3
11#include "bu/stream.h" 4#include "bu/stream.h"
5#include "bu/myriadstream.h"
12#include "bu/myriad.h" 6#include "bu/myriad.h"
13 7
14namespace Bu 8namespace Bu
15{ 9{
16 class MyriadStream : public Bu::Stream 10 class MyriadStream : public Bu::Stream
17 { 11 {
18 friend class Myriad; 12 friend class Myriad;
19 private: 13 private:
20 /** 14 MyriadStream( Bu::Myriad &rMyriad, Bu::Myriad::Stream *pStream,
21 * These can only be created by the Myriad class. 15 Bu::Myriad::Mode eMode );
22 */
23 MyriadStream( Myriad &rMyriad, Myriad::Stream *pStream );
24
25 public: 16 public:
26 virtual ~MyriadStream(); 17 virtual ~MyriadStream();
27 18
19 public:
28 virtual void close(); 20 virtual void close();
29 virtual Bu::size read( void *pBuf, Bu::size nBytes ); 21 virtual size read( void *pBuf, size iBytes );
30 virtual Bu::size write( const void *pBuf, Bu::size nBytes ); 22 virtual size write( const void *pBuf, size iBytes );
31 using Stream::write; 23 using Stream::write;
32 virtual Bu::size tell(); 24 virtual size tell();
33 virtual void seek( Bu::size offset ); 25 virtual void seek( size offset );
34 virtual void setPos( Bu::size pos ); 26 virtual void setPos( size pos );
35 virtual void setPosEnd( Bu::size pos ); 27 virtual void setPosEnd( size pos );
36 virtual bool isEos(); 28 virtual bool isEos();
37 virtual bool isOpen(); 29 virtual bool isOpen();
38 virtual void flush(); 30 virtual void flush();
@@ -43,18 +35,18 @@ namespace Bu
43 virtual bool isSeekable(); 35 virtual bool isSeekable();
44 virtual bool isBlocking(); 36 virtual bool isBlocking();
45 virtual void setBlocking( bool bBlocking=true ); 37 virtual void setBlocking( bool bBlocking=true );
46 virtual void setSize( Bu::size iSize ); 38 virtual void setSize( size iSize );
47
48 virtual size getSize() const; 39 virtual size getSize() const;
49 virtual size getBlockSize() const; 40 virtual size getBlockSize() const;
50 virtual Bu::String getLocation() const; 41 virtual Bu::String getLocation() const;
42 Myriad::StreamId getId() const;
51 43
52 private: 44 private:
53 Myriad &rMyriad; 45 mutable Bu::Mutex mAccess;
54 Myriad::Stream *pStream; 46 Bu::Myriad &rMyriad;
55 Myriad::Block *pCurBlock; 47 Bu::Myriad::Stream *pStream;
56 int iBlockSize; 48 Bu::Myriad::Mode eMode;
57 int iPos; 49 int32_t iPos;
58 }; 50 };
59}; 51};
60 52
diff --git a/src/tests/bigmyriad.cpp b/src/tests/bigmyriad.cpp
index 9af301c..73a3315 100644
--- a/src/tests/bigmyriad.cpp
+++ b/src/tests/bigmyriad.cpp
@@ -5,16 +5,17 @@
5int main() 5int main()
6{ 6{
7 Bu::File f("big.myr", Bu::File::Read|Bu::File::Write|Bu::File::Create ); 7 Bu::File f("big.myr", Bu::File::Read|Bu::File::Write|Bu::File::Create );
8 Bu::Myriad m( f, 2048 ); 8 Bu::Myriad m( f, 512, 12 );
9 9
10 char *buf = new char[1024*1024*10]; 10#define SSIZE (1024*8) // 1024*1024*10
11 memset( buf, 0, 1024*1024*10 ); 11 char *buf = new char[SSIZE];
12 12
13 for( int j = 0; j < 250; j++ ) 13 for( int j = 0; j < 25; j++ )
14 { 14 {
15 m.openStream( m.createStream() ).write( buf, 1024*1024*10 ); 15 memset( buf, j, SSIZE );
16// m.sync(); 16 m.create( Bu::Myriad::Write ).write( buf, SSIZE );
17 printf("\r%03d%%", (j+1)*100/250 ); 17// m.sync();
18 printf("\r%03d%%", (j+1)*100/25 );
18 fflush( stdout ); 19 fflush( stdout );
19 } 20 }
20 21
diff --git a/src/tests/cachedel.cpp b/src/tests/cachedel.cpp
index 817757c..f4cb1b5 100644
--- a/src/tests/cachedel.cpp
+++ b/src/tests/cachedel.cpp
@@ -21,6 +21,12 @@ public:
21 21
22 virtual ~Something() 22 virtual ~Something()
23 { 23 {
24 //Bu::println("Deleting %1").arg( this->toString() );
25 }
26
27 void sayHi()
28 {
29 Bu::println("Hello %1").arg( toString() );
24 } 30 }
25 31
26 virtual Bu::Uuid getKey() const 32 virtual Bu::Uuid getKey() const
@@ -39,7 +45,7 @@ public:
39 changed(); 45 changed();
40 } 46 }
41 47
42 virtual Bu::String toString() const=0; 48 virtual Bu::String toString() const=0;// { return Bu::String("ERROR"); };
43 49
44private: 50private:
45 Bu::Uuid uId; 51 Bu::Uuid uId;
@@ -60,6 +66,11 @@ public:
60 iNumber( iNumber ) 66 iNumber( iNumber )
61 { 67 {
62 } 68 }
69
70 virtual ~SubSomethingA()
71 {
72 Bu::println("Deleting-A %1").arg( this->toString() );
73 }
63 74
64 virtual Bu::String toString() const 75 virtual Bu::String toString() const
65 { 76 {
@@ -84,6 +95,10 @@ public:
84 sString( sString ) 95 sString( sString )
85 { 96 {
86 } 97 }
98
99 virtual ~SubSomethingB()
100 {
101 }
87 102
88 virtual Bu::String toString() const 103 virtual Bu::String toString() const
89 { 104 {
@@ -187,6 +202,11 @@ int main( int, char *[] )
187 Bu::MemBuf mbStore; 202 Bu::MemBuf mbStore;
188 SomethingCache c( mbStore ); 203 SomethingCache c( mbStore );
189 204
205 {
206 SubSomethingA a("Test", 1);
207 a.sayHi();
208 }
209
190 SomethingPtr ptr; 210 SomethingPtr ptr;
191 if( time(NULL)%2 ) 211 if( time(NULL)%2 )
192 ptr = c.insert( new SubSomethingA("Hello", 55) ).cast<Something>(); 212 ptr = c.insert( new SubSomethingA("Hello", 55) ).cast<Something>();
@@ -205,8 +225,13 @@ int main( int, char *[] )
205 225
206 SomethingPtr p2 = c.insert( new SubSomethingA("new test", 123) ).cast<Something>(); 226 SomethingPtr p2 = c.insert( new SubSomethingA("new test", 123) ).cast<Something>();
207 id = p2.getKey(); 227 id = p2.getKey();
228 Bu::println("p2 %1: %2").arg( id ).arg( c.has( id ) );
208 p2.unbind(); 229 p2.unbind();
230 Bu::println("p2 %1: %2").arg( id ).arg( c.has( id ) );
209 c.erase( id ); 231 c.erase( id );
232 Bu::println("p2 %1: %2").arg( id ).arg( c.has( id ) );
233
234 Bu::println("Program listing over, leaving main scope.");
210 235
211 return 0; 236 return 0;
212} 237}
diff --git a/src/tests/myriad.cpp b/src/tests/myriad.cpp
new file mode 100644
index 0000000..ee4eac4
--- /dev/null
+++ b/src/tests/myriad.cpp
@@ -0,0 +1,23 @@
1#include <bu/myriad.h>
2#include <bu/myriadstream.h>
3#include <bu/string.h>
4#include <bu/sio.h>
5#include <bu/file.h>
6
7int main( int , char *[] )
8{
9 Bu::File fMyriad("test.myr", Bu::File::WriteNew|Bu::File::Read );
10 Bu::Myriad m( fMyriad, 32 );
11
12 Bu::MyriadStream ms = m.create( Bu::Myriad::ReadWrite );
13 ms.setSize( 150 );
14 ms.setPos( 145 );
15 char stuff[10];
16 int32_t iRead = ms.read( stuff, 10 );
17
18 Bu::println("Tried to read 10, expect 5, got %1").arg( iRead );
19
20
21 return 0;
22}
23
diff --git a/src/tests/myriadfs.cpp b/src/tests/myriadfs.cpp
index 1266e4b..29ac3d9 100644
--- a/src/tests/myriadfs.cpp
+++ b/src/tests/myriadfs.cpp
@@ -9,7 +9,7 @@ using namespace Bu;
9int main() 9int main()
10{ 10{
11// Bu::MemBuf mb; 11// Bu::MemBuf mb;
12 Bu::File mb("store.myr", File::Read|File::Write|File::Create ); 12 Bu::File mb("store.mfs", File::Read|File::Write|File::Create );
13 Bu::MyriadFs mfs( mb, 512 ); 13 Bu::MyriadFs mfs( mb, 512 );
14 14
15 sio << "Creating dirs..." << sio.nl; 15 sio << "Creating dirs..." << sio.nl;
diff --git a/src/tools/myriad.cpp b/src/tools/myriad.cpp
index ccf3d3b..0dd9840 100644
--- a/src/tools/myriad.cpp
+++ b/src/tools/myriad.cpp
@@ -20,6 +20,7 @@ enum Mode
20 modeCreate, 20 modeCreate,
21 modeInfo, 21 modeInfo,
22 modeStreamNew, 22 modeStreamNew,
23 modeStreamErase,
23 modeStreamDump, 24 modeStreamDump,
24 modeStreamPut, 25 modeStreamPut,
25 modeStreamGet, 26 modeStreamGet,
@@ -44,6 +45,8 @@ public:
44 "Display some info about a Myriad file." ); 45 "Display some info about a Myriad file." );
45 addOption( eMode, 'n', "new", 46 addOption( eMode, 'n', "new",
46 "Create a new sub-stream in a Myriad file."); 47 "Create a new sub-stream in a Myriad file.");
48 addOption( eMode, 'e', "erase",
49 "Erase sub-stream in a Myriad file.");
47 addOption( eMode, 'd', "dump", 50 addOption( eMode, 'd', "dump",
48 "Display a hexdump of a stream from a Myriad file."); 51 "Display a hexdump of a stream from a Myriad file.");
49 addOption( eMode, "get", 52 addOption( eMode, "get",
@@ -67,6 +70,7 @@ public:
67 setOverride( "create", modeCreate ); 70 setOverride( "create", modeCreate );
68 setOverride( "info", modeInfo ); 71 setOverride( "info", modeInfo );
69 setOverride( "new", modeStreamNew ); 72 setOverride( "new", modeStreamNew );
73 setOverride( "erase", modeStreamErase );
70 setOverride( "dump", modeStreamDump ); 74 setOverride( "dump", modeStreamDump );
71 setOverride( "put", modeStreamPut ); 75 setOverride( "put", modeStreamPut );
72 setOverride( "get", modeStreamGet ); 76 setOverride( "get", modeStreamGet );
@@ -90,6 +94,49 @@ Bu::Formatter &operator>>( Bu::Formatter &f, Mode & /*e*/ )
90 return f; 94 return f;
91} 95}
92 96
97void printMap( const Bu::BitString &bs )
98{
99 for( int j = 0; j < bs.getSize(); j++ )
100 {
101 if( j>0 && (j%50) == 0 )
102 Bu::println("");
103 if( bs.getBit( j ) )
104 Bu::print("#");
105 else
106 Bu::print("-");
107 }
108 Bu::println("\n");
109}
110
111void printMap( const Bu::Array<int32_t> &bm )
112{
113 int iBigest = 0;
114 for( int j = 0; j < bm.getSize(); j++ )
115 {
116 if( iBigest < bm[j] )
117 iBigest = bm[j];
118 }
119 int iWidth = Bu::String("%1").arg( iBigest ).end().getSize();
120 Bu::String sEmpty;
121 for( int j = 0; j < iWidth; j++ )
122 {
123 sEmpty += '-';
124 }
125 int iBreakAt = 60/(iWidth+1);
126 for( int j = 0; j < bm.getSize(); j++ )
127 {
128 if( j>0 && (j%iBreakAt) == 0 )
129 Bu::println("");
130
131 if( bm[j] < 0 )
132 Bu::print("%1 ").arg( sEmpty, Bu::Fmt(2).right().fill(' '));
133 else
134 Bu::print("%1 ").arg( bm[j], Bu::Fmt(2).right().fill(' '));
135
136 }
137 Bu::println("\n");
138}
139
93int main( int argc, char *argv[] ) 140int main( int argc, char *argv[] )
94{ 141{
95 Options opts( argc, argv ); 142 Options opts( argc, argv );
@@ -121,14 +168,14 @@ int main( int argc, char *argv[] )
121 Myriad m( fIn ); 168 Myriad m( fIn );
122 sio << "Myriad info:" << sio.nl 169 sio << "Myriad info:" << sio.nl
123 << " Block size: " << m.getBlockSize() << sio.nl 170 << " Block size: " << m.getBlockSize() << sio.nl
124 << " Block count: " << m.getNumBlocks() << sio.nl 171 << " Block count: " << m.getTotalBlocks() << sio.nl
125 << " Blocks used: " << m.getNumUsedBlocks() << " (" 172 << " Blocks used: " << m.getUsedBlocks() << " ("
126 << m.getNumUsedBlocks()*100/m.getNumBlocks() << "%)" 173 << m.getUsedBlocks()*100/m.getTotalBlocks() << "%)"
127 << sio.nl 174 << sio.nl
128 << " Stream count: " << m.getNumStreams() << sio.nl 175 << " Stream count: " << m.getTotalStreams() << sio.nl
129 << " Used space: " << m.getTotalUsedBytes() << sio.nl 176 << " Used space: " << m.getTotalUsedBytes() << sio.nl
130 << " Unused space: " << m.getTotalUnusedBytes() << sio.nl 177 << " Unused space: " << m.getTotalUnusedBytes() << sio.nl
131 << " % of files: " << (double)(m.getNumBlocks()*m.getBlockSize())/(double)(m.getTotalUsedBytes() + m.getTotalUnusedBytes( 4096 ))*100.0 << sio.nl; 178 << " % of files: " << (double)(m.getTotalBlocks()*m.getBlockSize())/(double)(m.getTotalUsedBytes() + m.getTotalUnusedBytes( 4096 ))*100.0 << sio.nl;
132/* Bu::Array<int> aStreams = m.getStreamIds(); 179/* Bu::Array<int> aStreams = m.getStreamIds();
133 sio << " Stream info:" << sio.nl; 180 sio << " Stream info:" << sio.nl;
134 for( Bu::Array<int>::iterator i = aStreams.begin(); i; i++ ) 181 for( Bu::Array<int>::iterator i = aStreams.begin(); i; i++ )
@@ -149,7 +196,23 @@ int main( int argc, char *argv[] )
149 { 196 {
150 File fOut( opts.sFile, File::Write|File::Read ); 197 File fOut( opts.sFile, File::Write|File::Read );
151 Myriad m( fOut ); 198 Myriad m( fOut );
152 m.createStream( opts.iPreallocate ); 199 m.create( Bu::Myriad::WriteNew, opts.iPreallocate );
200 }
201 break;
202
203 case modeStreamErase:
204 if( !opts.sFile.isSet() )
205 {
206 sio << "Please specify a file manipulate." << sio.nl;
207 return 0;
208 }
209 else
210 {
211 File fOut( opts.sFile, File::Write|File::Read );
212 Myriad m( fOut );
213 m.erase( opts.iStream );
214 printMap( m.buildBlockUseMap() );
215 printMap( m.buildBlockMap() );
153 } 216 }
154 break; 217 break;
155 218
@@ -163,7 +226,7 @@ int main( int argc, char *argv[] )
163 { 226 {
164 File fOut( opts.sFile, File::Read ); 227 File fOut( opts.sFile, File::Read );
165 Myriad m( fOut ); 228 Myriad m( fOut );
166 MyriadStream s = m.openStream( opts.iStream ); 229 MyriadStream s = m.open( opts.iStream, Bu::Myriad::Read );
167 sio << "Stream " << opts.iStream << ":" << sio.nl; 230 sio << "Stream " << opts.iStream << ":" << sio.nl;
168 char buf[8]; 231 char buf[8];
169 int iPos = 0; 232 int iPos = 0;
@@ -210,8 +273,8 @@ int main( int argc, char *argv[] )
210 { 273 {
211 File fOut( opts.sFile, File::Write|File::Read ); 274 File fOut( opts.sFile, File::Write|File::Read );
212 Myriad m( fOut ); 275 Myriad m( fOut );
213 MyriadStream sOut = m.openStream( 276 MyriadStream sOut = m.create(
214 m.createStream( opts.iPreallocate ) 277 Bu::Myriad::WriteNew, opts.iPreallocate
215 ); 278 );
216 File fIn( opts.sSrc, File::Read ); 279 File fIn( opts.sSrc, File::Read );
217 char buf[1024]; 280 char buf[1024];
@@ -236,7 +299,7 @@ int main( int argc, char *argv[] )
236 { 299 {
237 File fIn( opts.sFile, File::Write|File::Read ); 300 File fIn( opts.sFile, File::Write|File::Read );
238 Myriad m( fIn ); 301 Myriad m( fIn );
239 MyriadStream sIn = m.openStream( opts.iStream ); 302 MyriadStream sIn = m.open( opts.iStream, Bu::Myriad::Read );
240 File fOut( opts.sDst, File::Write|File::Create|File::Truncate ); 303 File fOut( opts.sDst, File::Write|File::Create|File::Truncate );
241 char buf[1024]; 304 char buf[1024];
242 while( !sIn.isEos() ) 305 while( !sIn.isEos() )
@@ -255,17 +318,8 @@ int main( int argc, char *argv[] )
255 { 318 {
256 File fIn( opts.sFile, File::Write|File::Read ); 319 File fIn( opts.sFile, File::Write|File::Read );
257 Myriad m( fIn ); 320 Myriad m( fIn );
258 Bu::BitString bs = m.getBlocksUsed(); 321 printMap( m.buildBlockUseMap() );
259 for( int j = 0; j < bs.getSize(); j++ ) 322 printMap( m.buildBlockMap() );
260 {
261 if( j>0 && (j%50) == 0 )
262 Bu::println("");
263 if( bs.getBit( j ) )
264 Bu::print("#");
265 else
266 Bu::print("-");
267 }
268 Bu::println("\n");
269 } 323 }
270 break; 324 break;
271 325
@@ -277,4 +331,3 @@ int main( int argc, char *argv[] )
277 331
278 return 0; 332 return 0;
279} 333}
280
diff --git a/src/unit/myriad.unit b/src/unit/myriad.unit
index 24d3116..f7bea97 100644
--- a/src/unit/myriad.unit
+++ b/src/unit/myriad.unit
@@ -109,7 +109,7 @@ suite Myriad
109 File fMyriad = tempFile( sFileName ); 109 File fMyriad = tempFile( sFileName );
110 Myriad m( fMyriad, 32 ); 110 Myriad m( fMyriad, 32 );
111 111
112 MyriadStream ms = m.openStream( m.createStream() ); 112 MyriadStream ms = m.create( Myriad::ReadWrite );
113 ms.setSize( 150 ); 113 ms.setSize( 150 );
114 ms.setPos( 145 ); 114 ms.setPos( 145 );
115 char stuff[10]; 115 char stuff[10];
@@ -163,7 +163,7 @@ suite Myriad
163 if( iSize < 8 || iSize > 1024 ) 163 if( iSize < 8 || iSize > 1024 )
164 throw ExceptionBase("Read bad data, %d", iSize ); 164 throw ExceptionBase("Read bad data, %d", iSize );
165 char *buf = new char[iSize-8]; 165 char *buf = new char[iSize-8];
166 if( s.read( buf, iSize-8 ) < (size_t)iSize-8 ) 166 if( s.read( buf, iSize-8 ) < (Bu::size)iSize-8 )
167 { 167 {
168 delete[] buf; 168 delete[] buf;
169 throw ExceptionBase("Block failed verify (insuffient block data)."); 169 throw ExceptionBase("Block failed verify (insuffient block data).");
@@ -197,13 +197,12 @@ suite Myriad
197 String sFileName("myriad-XXXXXXX"); 197 String sFileName("myriad-XXXXXXX");
198 198
199 File fMyriad = tempFile( sFileName ); 199 File fMyriad = tempFile( sFileName );
200 Myriad m( fMyriad ); 200 Myriad m( fMyriad, 64 );
201 m.initialize( 64 );
202 201
203 Array<int> aStreams; 202 Array<int> aStreams;
204 for( int j = 0; j < 5; j++ ) 203 for( int j = 0; j < 5; j++ )
205 { 204 {
206 aStreams.append( m.createStream() ); 205 aStreams.append( m.create( Bu::Myriad::Read ).getId() );
207 } 206 }
208 207
209 srandom( 512 ); 208 srandom( 512 );
@@ -213,7 +212,7 @@ suite Myriad
213 switch( random()%5 ) 212 switch( random()%5 )
214 { 213 {
215 case 0: 214 case 0:
216 aStreams.append( m.createStream() ); 215 aStreams.append( m.create( Bu::Myriad::Read ).getId() );
217 break; 216 break;
218 217
219 case 1: 218 case 1:
@@ -221,10 +220,10 @@ suite Myriad
221 { 220 {
222 int iStream = random()%aStreams.getSize(); 221 int iStream = random()%aStreams.getSize();
223 { 222 {
224 MyriadStream ms = m.openStream( aStreams[iStream] ); 223 MyriadStream ms = m.open( aStreams[iStream], Myriad::Read );
225 verifyStream( ms ); 224 verifyStream( ms );
226 } 225 }
227 m.deleteStream( aStreams[iStream] ); 226 m.erase( aStreams[iStream] );
228 Array<int>::iterator i = aStreams.begin(); 227 Array<int>::iterator i = aStreams.begin();
229 for( int k = 0; k < iStream; k++ ) 228 for( int k = 0; k < iStream; k++ )
230 i++; 229 i++;
@@ -235,11 +234,13 @@ suite Myriad
235 default: 234 default:
236 if( aStreams.getSize() == 0 ) 235 if( aStreams.getSize() == 0 )
237 { 236 {
238 aStreams.append( m.createStream() ); 237 aStreams.append(
238 m.create( Bu::Myriad::Read ).getId()
239 );
239 } 240 }
240 { 241 {
241 int iStream = random()%aStreams.getSize(); 242 int iStream = random()%aStreams.getSize();
242 MyriadStream ms = m.openStream( aStreams[iStream] ); 243 MyriadStream ms = m.open( aStreams[iStream], Myriad::ReadWrite );
243 addBlock( ms ); 244 addBlock( ms );
244 verifyStream( ms ); 245 verifyStream( ms );
245 } 246 }
@@ -249,7 +250,7 @@ suite Myriad
249 250
250 for( Array<int>::iterator i = aStreams.begin(); i; i++ ) 251 for( Array<int>::iterator i = aStreams.begin(); i; i++ )
251 { 252 {
252 MyriadStream ms = m.openStream( *i ); 253 MyriadStream ms = m.open( *i, Myriad::Read );
253 verifyStream( ms ); 254 verifyStream( ms );
254 } 255 }
255 } 256 }
@@ -259,14 +260,13 @@ suite Myriad
259 String sFileName("myriad-XXXXXXX"); 260 String sFileName("myriad-XXXXXXX");
260 261
261 File fMyriad = tempFile( sFileName ); 262 File fMyriad = tempFile( sFileName );
262 Myriad m( fMyriad ); 263 Myriad m( fMyriad, 128 );
263 m.initialize( 128 );
264 264
265 Array<int> aStream; 265 Array<int> aStream;
266 266
267 for( int j = 0; j < 5; j++ ) 267 for( int j = 0; j < 5; j++ )
268 { 268 {
269 aStream.append( m.createStream() ); 269 aStream.append( m.create( Bu::Myriad::Read ).getId() );
270 } 270 }
271 271
272 srandom( 1024 ); 272 srandom( 1024 );
@@ -276,7 +276,7 @@ suite Myriad
276 { 276 {
277 for( Array<int>::iterator i = aStream.begin(); i; i++ ) 277 for( Array<int>::iterator i = aStream.begin(); i; i++ )
278 { 278 {
279 MyriadStream ms = m.openStream( *i ); 279 MyriadStream ms = m.open( *i, Myriad::ReadWrite );
280 addBlock( ms, false ); 280 addBlock( ms, false );
281 ms.setSize( ms.tell() ); 281 ms.setSize( ms.tell() );
282 unitTest( ms.read( &b, 1 ) == 0 ); 282 unitTest( ms.read( &b, 1 ) == 0 );
@@ -301,7 +301,7 @@ suite Myriad
301 301
302 for( int j = 0; j < 5; j++ ) 302 for( int j = 0; j < 5; j++ )
303 { 303 {
304 aStream.append( m.createStream() ); 304 aStream.append( m.create( Bu::Myriad::Read ).getId() );
305 incProgress(); 305 incProgress();
306 } 306 }
307 } 307 }
@@ -315,7 +315,7 @@ suite Myriad
315 Myriad m( fMyriad ); 315 Myriad m( fMyriad );
316 for( Array<int>::iterator i = aStream.begin(); i; i++ ) 316 for( Array<int>::iterator i = aStream.begin(); i; i++ )
317 { 317 {
318 MyriadStream ms = m.openStream( *i ); 318 MyriadStream ms = m.open( *i, Myriad::ReadWrite );
319 addBlock( ms, false ); 319 addBlock( ms, false );
320 ms.setSize( ms.tell() ); 320 ms.setSize( ms.tell() );
321 unitTest( ms.read( &b, 1 ) == 0 ); 321 unitTest( ms.read( &b, 1 ) == 0 );
@@ -342,17 +342,17 @@ suite Myriad
342 342
343 for( int j = 0; j < 15; j++ ) 343 for( int j = 0; j < 15; j++ )
344 { 344 {
345 int iStream = m.createStream(); 345 MyriadStream ms = m.create( Myriad::Write );
346 int iStream = ms.getId();
346 aStream.append( iStream ); 347 aStream.append( iStream );
347 VerifyObject vo( random()%1024 ); 348 VerifyObject vo( random()%1024 );
348 { 349 {
349 MyriadStream ms = m.openStream( iStream );
350 Archive ar( ms, Archive::save ); 350 Archive ar( ms, Archive::save );
351 ar << vo; 351 ar << vo;
352 unitTest( ms.tell() == vo.getBytesWritten() ); 352 unitTest( ms.tell() == vo.getBytesWritten() );
353 ms.setSize( ms.tell() ); 353 ms.setSize( ms.tell() );
354 } 354 }
355 unitTest( m.getStreamSize( iStream ) == vo.getBytesWritten() ); 355 unitTest( m.getSize( iStream ) == vo.getBytesWritten() );
356 incProgress(); 356 incProgress();
357 } 357 }
358 } 358 }
@@ -365,18 +365,18 @@ suite Myriad
365 { 365 {
366 VerifyObject vo( random()%1024 ); 366 VerifyObject vo( random()%1024 );
367 { 367 {
368 MyriadStream ms = m.openStream( *i ); 368 MyriadStream ms = m.open( *i, Myriad::Read );
369 Archive ar( ms, Archive::load ); 369 Archive ar( ms, Archive::load );
370 ar >> vo; 370 ar >> vo;
371 } 371 }
372 { 372 {
373 MyriadStream ms = m.openStream( *i ); 373 MyriadStream ms = m.open( *i, Myriad::WriteNew );
374 Archive ar( ms, Archive::save ); 374 Archive ar( ms, Archive::save );
375 ar << vo; 375 ar << vo;
376 unitTest( ms.tell() == vo.getBytesWritten() ); 376 unitTest( ms.tell() == vo.getBytesWritten() );
377 ms.setSize( ms.tell() ); 377 ms.setSize( ms.tell() );
378 } 378 }
379 unitTest( m.getStreamSize( *i ) == vo.getBytesWritten() ); 379 unitTest( m.getSize( *i ) == vo.getBytesWritten() );
380 incProgress(); 380 incProgress();
381 } 381 }
382 } 382 }
diff --git a/src/unstable/bitstring.cpp b/src/unstable/bitstring.cpp
index 21c1316..b80c073 100644
--- a/src/unstable/bitstring.cpp
+++ b/src/unstable/bitstring.cpp
@@ -209,7 +209,7 @@ void Bu::BitString::flipBit( long iBit )
209 caData[iBit/8] ^= (1<<(iBit%8)); 209 caData[iBit/8] ^= (1<<(iBit%8));
210} 210}
211 211
212bool Bu::BitString::getBit( long iBit ) 212bool Bu::BitString::getBit( long iBit ) const
213{ 213{
214 if( iBit >= iBits || iBit < 0 ) return false; 214 if( iBit >= iBits || iBit < 0 ) return false;
215 if( (caData[iBit/8] & (1<<(iBit%8))) == 0 ) 215 if( (caData[iBit/8] & (1<<(iBit%8))) == 0 )
@@ -224,7 +224,7 @@ long Bu::BitString::getBitLength()
224 return iBits; 224 return iBits;
225} 225}
226 226
227long Bu::BitString::getSize() 227long Bu::BitString::getSize() const
228{ 228{
229 return iBits; 229 return iBits;
230} 230}
@@ -311,6 +311,14 @@ void Bu::BitString::clear()
311 } 311 }
312} 312}
313 313
314void Bu::BitString::fill()
315{
316 if( caData != NULL )
317 {
318 memset( caData, 0xff, iBytes );
319 }
320}
321
314bool Bu::BitString::setBitLength( long iLength, bool bClear ) 322bool Bu::BitString::setBitLength( long iLength, bool bClear )
315{ 323{
316 return setSize( iLength, bClear ); 324 return setSize( iLength, bClear );
diff --git a/src/unstable/bitstring.h b/src/unstable/bitstring.h
index afc22fb..70ba822 100644
--- a/src/unstable/bitstring.h
+++ b/src/unstable/bitstring.h
@@ -88,7 +88,7 @@ namespace Bu
88 *@param iBit The index of the bit to test. 88 *@param iBit The index of the bit to test.
89 *@returns True for a 1, false for a 0. 89 *@returns True for a 1, false for a 0.
90 */ 90 */
91 bool getBit( long iBit ); 91 bool getBit( long iBit ) const;
92 92
93 /** 93 /**
94 * Inverts the entire BitString, in effect this calls flipBit on every 94 * Inverts the entire BitString, in effect this calls flipBit on every
@@ -106,7 +106,7 @@ namespace Bu
106 DEPRECATED 106 DEPRECATED
107 long getBitLength(); 107 long getBitLength();
108 108
109 long getSize(); 109 long getSize() const;
110 110
111 /** 111 /**
112 * Sets the entire BitString to zeros, but it does it very quickly. 112 * Sets the entire BitString to zeros, but it does it very quickly.
@@ -115,6 +115,12 @@ namespace Bu
115 void clear(); 115 void clear();
116 116
117 /** 117 /**
118 * Sets the entire BitString to ones, but it does it very quickly.
119 * This operation runs in O(N).
120 */
121 void fill();
122
123 /**
118 * Gets another BitString that is autonomous of the current one 124 * Gets another BitString that is autonomous of the current one
119 * (contains a copy of the memory, not a pointer) and contains a subset 125 * (contains a copy of the memory, not a pointer) and contains a subset
120 * of the data in the current BitString. This is an inclusive 126 * of the data in the current BitString. This is an inclusive
diff --git a/src/unstable/cachebase.h b/src/unstable/cachebase.h
index ec73ede..830f5fe 100644
--- a/src/unstable/cachebase.h
+++ b/src/unstable/cachebase.h
@@ -32,11 +32,15 @@ namespace Bu
32 bDeleted( false ), 32 bDeleted( false ),
33 pObject( pObject ) 33 pObject( pObject )
34 { 34 {
35 //Bu::println("CacheEntry::CacheEntry: registering pObject (0x%1)").
36 // arg( reinterpret_cast<ptrdiff_t>(pObject), Bu::Fmt::hex() );
35 } 37 }
36 38
37 virtual ~CacheEntry() 39 virtual ~CacheEntry()
38 { 40 {
39 mEntry.lock(); 41 mEntry.lock();
42 //Bu::println("CacheEntry::~CacheEntry: deleting pObject (0x%1)").
43 // arg( reinterpret_cast<ptrdiff_t>(pObject), Bu::Fmt::hex() );
40 delete pObject; 44 delete pObject;
41 mEntry.unlock(); 45 mEntry.unlock();
42 } 46 }
@@ -497,7 +501,7 @@ namespace Bu
497 if( pEnt->iRefCount == 0 ) 501 if( pEnt->iRefCount == 0 )
498 { 502 {
499 pEnt->mEntry.unlock(); 503 pEnt->mEntry.unlock();
500 delete pEnt->pObject; 504 //delete pEnt->pObject;
501 delete pEnt; 505 delete pEnt;
502 } 506 }
503 else 507 else
@@ -529,7 +533,7 @@ namespace Bu
529 pEnt->mEntry.unlock(); 533 pEnt->mEntry.unlock();
530 throw Bu::ExceptionBase( Bu::String("Cache entry %1 cannot be erased, there are %2 active references.").arg( key ).arg( iCount ).end().getStr() ); 534 throw Bu::ExceptionBase( Bu::String("Cache entry %1 cannot be erased, there are %2 active references.").arg( key ).arg( iCount ).end().getStr() );
531 } 535 }
532 delete pEnt->pObject; 536 //delete pEnt->pObject;
533 delete pEnt; 537 delete pEnt;
534 hCacheEntry.erase( key ); 538 hCacheEntry.erase( key );
535 } 539 }
@@ -559,7 +563,7 @@ namespace Bu
559 { 563 {
560 if( pEnt->isReadyForCleanup() ) 564 if( pEnt->isReadyForCleanup() )
561 { 565 {
562 delete pEnt->pObject; 566 //delete pEnt->pObject;
563 delete pEnt; 567 delete pEnt;
564 } 568 }
565 } 569 }
diff --git a/src/unstable/myriadcache.h b/src/unstable/myriadcache.h
index 24002b0..3629005 100644
--- a/src/unstable/myriadcache.h
+++ b/src/unstable/myriadcache.h
@@ -28,7 +28,9 @@ namespace Bu
28 try 28 try
29 { 29 {
30 Bu::ReadWriteMutex::ReadLocker l( rwStore ); 30 Bu::ReadWriteMutex::ReadLocker l( rwStore );
31 Bu::MyriadStream ms = mStore.openStream( 1 ); 31 Bu::MyriadStream ms = mStore.open(
32 1, Bu::Myriad::Read
33 );
32 Bu::Archive ar( ms, Bu::Archive::load ); 34 Bu::Archive ar( ms, Bu::Archive::load );
33 uint8_t uVer; 35 uint8_t uVer;
34 ar >> uVer; 36 ar >> uVer;
@@ -41,10 +43,15 @@ namespace Bu
41 } 43 }
42 catch(...) 44 catch(...)
43 { 45 {
44 if( mStore.createStreamWithId( 1 ) != 1 ) 46 try
47 {
48 mStore.open( 1, Bu::Myriad::Create|Bu::Myriad::ReadWrite );
49 _sync();
50 }
51 catch(...)
52 {
45 throw Bu::ExceptionBase("Error creating index stream."); 53 throw Bu::ExceptionBase("Error creating index stream.");
46 54 }
47 _sync();
48 } 55 }
49 } 56 }
50 57
@@ -78,7 +85,10 @@ namespace Bu
78 virtual void _create( const obtype *o ) 85 virtual void _create( const obtype *o )
79 { 86 {
80 Bu::ReadWriteMutex::WriteLocker wl( rwStore ); 87 Bu::ReadWriteMutex::WriteLocker wl( rwStore );
81 hIndex.insert( o->getKey(), mStore.createStream() ); 88 {
89 Bu::Myriad::StreamId id = mStore.allocate();
90 hIndex.insert( o->getKey(), id );
91 }
82 _save( o ); 92 _save( o );
83 93
84 bStructureChanged = true; 94 bStructureChanged = true;
@@ -87,7 +97,7 @@ namespace Bu
87 virtual void _erase( const keytype &k ) 97 virtual void _erase( const keytype &k )
88 { 98 {
89 Bu::ReadWriteMutex::WriteLocker wl( rwStore ); 99 Bu::ReadWriteMutex::WriteLocker wl( rwStore );
90 mStore.deleteStream( hIndex.get( k ) ); 100 mStore.erase( hIndex.get( k ) );
91 hIndex.erase( k ); 101 hIndex.erase( k );
92 102
93 bStructureChanged = true; 103 bStructureChanged = true;
@@ -98,13 +108,13 @@ namespace Bu
98 const keytype &k 108 const keytype &k
99 ) 109 )
100 { 110 {
101 Bu::MyriadStream ms = mStore.openStream( hIndex.get( k ) ); 111 Bu::MyriadStream ms = mStore.open( hIndex.get( k ), Bu::Myriad::Read );
102 return _cacheObjectLoad<keytype, obtype>( initObj, k, ms ); 112 return _cacheObjectLoad<keytype, obtype>( initObj, k, ms );
103 } 113 }
104 114
105 virtual void _save( const obtype *o ) 115 virtual void _save( const obtype *o )
106 { 116 {
107 Bu::MyriadStream ms = mStore.openStream( hIndex.get( o->getKey() ) ); 117 Bu::MyriadStream ms = mStore.open( hIndex.get( o->getKey() ), Bu::Myriad::WriteNew );
108 _cacheObjectSave( ms, o ); 118 _cacheObjectSave( ms, o );
109 ms.setSize( ms.tell() ); 119 ms.setSize( ms.tell() );
110 120
@@ -117,7 +127,7 @@ namespace Bu
117 if( !bStructureChanged ) 127 if( !bStructureChanged )
118 return; 128 return;
119 129
120 Bu::MyriadStream ms = mStore.openStream( 1 ); 130 Bu::MyriadStream ms = mStore.open( 1, Bu::Myriad::WriteNew );
121 Bu::Archive ar( ms, Bu::Archive::save ); 131 Bu::Archive ar( ms, Bu::Archive::save );
122 ar << (uint8_t)0 << hIndex; 132 ar << (uint8_t)0 << hIndex;
123 ar.close(); 133 ar.close();
diff --git a/src/unstable/myriadfs.cpp b/src/unstable/myriadfs.cpp
index b24997a..f748a53 100644
--- a/src/unstable/myriadfs.cpp
+++ b/src/unstable/myriadfs.cpp
@@ -8,6 +8,7 @@
8#include "bu/config.h" 8#include "bu/config.h"
9#include "bu/myriadfs.h" 9#include "bu/myriadfs.h"
10#include "bu/myriadstream.h" 10#include "bu/myriadstream.h"
11#include "bu/mutexlocker.h"
11 12
12#include <string.h> 13#include <string.h>
13#include <unistd.h> 14#include <unistd.h>
@@ -32,10 +33,10 @@ Bu::MyriadFs::MyriadFs( Bu::Stream &rStore, int iBlockSize ) :
32 iGroup = getgid(); 33 iGroup = getgid();
33#endif 34#endif
34 35
35 if( mStore.hasStream( 1 ) ) 36 if( mStore.exists( 1 ) )
36 { 37 {
37 // Check to see if this is a MyriadFs stream. 38 // Check to see if this is a MyriadFs stream.
38 Bu::MyriadStream ms = mStore.openStream( 1 ); 39 Bu::MyriadStream ms = mStore.open( 1, Bu::Myriad::Read );
39 char sMagic[4]; 40 char sMagic[4];
40 if( ms.read( sMagic, 4 ) < 4 ) 41 if( ms.read( sMagic, 4 ) < 4 )
41 throw MyriadFsException("The provided stream does not appear to be " 42 throw MyriadFsException("The provided stream does not appear to be "
@@ -62,8 +63,8 @@ Bu::MyriadFs::MyriadFs( Bu::Stream &rStore, int iBlockSize ) :
62 { 63 {
63 // Create initial header stream 64 // Create initial header stream
64 { 65 {
65 mStore.createStream( 1 ); 66 Bu::MyriadStream ms = mStore.open(
66 Bu::MyriadStream ms = mStore.openStream( 1 ); 67 1, Bu::Myriad::WriteNew|Bu::Myriad::Exclusive );
67 ms.write( Myriad_Fs_MAGIC_CODE, 4 ); 68 ms.write( Myriad_Fs_MAGIC_CODE, 4 );
68 int8_t iVer = 1; 69 int8_t iVer = 1;
69 int32_t iTmp = 1; 70 int32_t iTmp = 1;
@@ -77,8 +78,8 @@ Bu::MyriadFs::MyriadFs( Bu::Stream &rStore, int iBlockSize ) :
77 78
78 // Create initial inode stream, with one root node. 79 // Create initial inode stream, with one root node.
79 { 80 {
80 mStore.createStream( 2 ); 81 Bu::MyriadStream ms = mStore.open(
81 Bu::MyriadStream ms = mStore.openStream( 2 ); 82 2, Bu::Myriad::WriteNew|Bu::Myriad::Exclusive );
82 RawStat rs; 83 RawStat rs;
83 rs.iNode = 0; 84 rs.iNode = 0;
84 rs.iUser = iUser; 85 rs.iUser = iUser;
@@ -92,8 +93,8 @@ Bu::MyriadFs::MyriadFs( Bu::Stream &rStore, int iBlockSize ) :
92 93
93 // Create inode 0's storage stream. 94 // Create inode 0's storage stream.
94 { 95 {
95 mStore.createStream( 3 ); 96 Bu::MyriadStream ms = mStore.open(
96 Bu::MyriadStream ms = mStore.openStream( 3 ); 97 3, Bu::Myriad::WriteNew|Bu::Myriad::Exclusive );
97 int32_t iTmp32 = 0; 98 int32_t iTmp32 = 0;
98 ms.write( &iTmp32, 4 ); // iChildCount 99 ms.write( &iTmp32, 4 ); // iChildCount
99 } 100 }
@@ -107,15 +108,17 @@ Bu::MyriadFs::~MyriadFs()
107 108
108void Bu::MyriadFs::stat( const Bu::String &sPath, Bu::MyriadFs::Stat &rBuf ) 109void Bu::MyriadFs::stat( const Bu::String &sPath, Bu::MyriadFs::Stat &rBuf )
109{ 110{
111 Bu::MutexLocker lLock( mAccess );
110 int32_t iParent; 112 int32_t iParent;
111 int32_t iNode = lookupInode( sPath, iParent ); 113 int32_t iNode = lookupInode( sPath, iParent );
112 Bu::MyriadStream is = mStore.openStream( 2 ); 114 Bu::MyriadStream is = mStore.open( 2, Bu::Myriad::Read );
113 stat( iNode, rBuf, is ); 115 stat( iNode, rBuf, is );
114} 116}
115 117
116Bu::MyriadStream Bu::MyriadFs::open( const Bu::String &sPath, int iMode, 118Bu::MyriadStream Bu::MyriadFs::open( const Bu::String &sPath, int iMode,
117 uint16_t uPerms ) 119 uint16_t uPerms )
118{ 120{
121 Bu::MutexLocker lLock( mAccess );
119 int32_t iParent = -1; 122 int32_t iParent = -1;
120 int32_t iNode; 123 int32_t iNode;
121 try 124 try
@@ -164,6 +167,7 @@ void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms,
164void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms, 167void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms,
165 uint32_t uSpecial ) 168 uint32_t uSpecial )
166{ 169{
170 Bu::MutexLocker lLock( mAccess );
167 int32_t iParent = -1; 171 int32_t iParent = -1;
168// int32_t iNode; 172// int32_t iNode;
169 try 173 try
@@ -200,6 +204,7 @@ void Bu::MyriadFs::mkDir( const Bu::String &sPath, uint16_t iPerms )
200void Bu::MyriadFs::mkSymLink( const Bu::String &sTarget, 204void Bu::MyriadFs::mkSymLink( const Bu::String &sTarget,
201 const Bu::String &sPath ) 205 const Bu::String &sPath )
202{ 206{
207 Bu::MutexLocker lLock( mAccess );
203 int32_t iParent = -1; 208 int32_t iParent = -1;
204 int32_t iNode; 209 int32_t iNode;
205 try 210 try
@@ -232,6 +237,7 @@ void Bu::MyriadFs::mkSymLink( const Bu::String &sTarget,
232void Bu::MyriadFs::mkHardLink( const Bu::String &sTarget, 237void Bu::MyriadFs::mkHardLink( const Bu::String &sTarget,
233 const Bu::String &sPath ) 238 const Bu::String &sPath )
234{ 239{
240 Bu::MutexLocker lLock( mAccess );
235 int32_t iParent = -1; 241 int32_t iParent = -1;
236 int32_t iNode; 242 int32_t iNode;
237 243
@@ -257,7 +263,7 @@ void Bu::MyriadFs::mkHardLink( const Bu::String &sTarget,
257// sio << "End filename: " << sName << sio.nl; 263// sio << "End filename: " << sName << sio.nl;
258// sio << "Parent inode: " << iParent << sio.nl; 264// sio << "Parent inode: " << iParent << sio.nl;
259 addToDir( iParent, iNode, sName ); 265 addToDir( iParent, iNode, sName );
260 MyriadStream is = mStore.openStream( 2 ); 266 MyriadStream is = mStore.open( 2, Bu::Myriad::ReadWrite );
261 RawStat rs; 267 RawStat rs;
262 readInode( iNode, rs, is ); 268 readInode( iNode, rs, is );
263 rs.iLinks++; 269 rs.iLinks++;
@@ -267,6 +273,7 @@ void Bu::MyriadFs::mkHardLink( const Bu::String &sTarget,
267 273
268Bu::String Bu::MyriadFs::readSymLink( const Bu::String &sPath ) 274Bu::String Bu::MyriadFs::readSymLink( const Bu::String &sPath )
269{ 275{
276 Bu::MutexLocker lLock( mAccess );
270 int32_t iParent = -1; 277 int32_t iParent = -1;
271 int32_t iNode; 278 int32_t iNode;
272 iNode = lookupInode( sPath, iParent ); 279 iNode = lookupInode( sPath, iParent );
@@ -279,6 +286,7 @@ Bu::String Bu::MyriadFs::readSymLink( const Bu::String &sPath )
279 286
280Bu::MyriadFs::Dir Bu::MyriadFs::readDir( const Bu::String &sPath ) 287Bu::MyriadFs::Dir Bu::MyriadFs::readDir( const Bu::String &sPath )
281{ 288{
289 Bu::MutexLocker lLock( mAccess );
282 int32_t iParent = -1; 290 int32_t iParent = -1;
283 int32_t iNode = lookupInode( sPath, iParent ); 291 int32_t iNode = lookupInode( sPath, iParent );
284 return readDir( iNode ); 292 return readDir( iNode );
@@ -287,6 +295,7 @@ Bu::MyriadFs::Dir Bu::MyriadFs::readDir( const Bu::String &sPath )
287void Bu::MyriadFs::setTimes( const Bu::String &sPath, int64_t iATime, 295void Bu::MyriadFs::setTimes( const Bu::String &sPath, int64_t iATime,
288 int64_t iMTime ) 296 int64_t iMTime )
289{ 297{
298 Bu::MutexLocker lLock( mAccess );
290 int32_t iParent = -1; 299 int32_t iParent = -1;
291 int32_t iNode; 300 int32_t iNode;
292 301
@@ -297,6 +306,7 @@ void Bu::MyriadFs::setTimes( const Bu::String &sPath, int64_t iATime,
297 306
298void Bu::MyriadFs::unlink( const Bu::String &sPath ) 307void Bu::MyriadFs::unlink( const Bu::String &sPath )
299{ 308{
309 Bu::MutexLocker lLock( mAccess );
300 int32_t iParent = -1; 310 int32_t iParent = -1;
301// int32_t iNode; 311// int32_t iNode;
302 312
@@ -314,7 +324,9 @@ void Bu::MyriadFs::unlink( const Bu::String &sPath )
314 readInode( (*i).iNode, rs ); 324 readInode( (*i).iNode, rs );
315 if( (rs.uPerms&typeMask) == typeDir ) 325 if( (rs.uPerms&typeMask) == typeDir )
316 { 326 {
317 MyriadStream msDir = mStore.openStream( rs.uStreamIndex ); 327 MyriadStream msDir = mStore.open(
328 rs.uStreamIndex, Bu::Myriad::Read
329 );
318 int32_t iCount; 330 int32_t iCount;
319 msDir.read( &iCount, 4 ); 331 msDir.read( &iCount, 4 );
320 if( iCount > 0 ) 332 if( iCount > 0 )
@@ -350,6 +362,7 @@ void Bu::MyriadFs::unlink( const Bu::String &sPath )
350 362
351void Bu::MyriadFs::setFileSize( const Bu::String &sPath, int32_t iSize ) 363void Bu::MyriadFs::setFileSize( const Bu::String &sPath, int32_t iSize )
352{ 364{
365 Bu::MutexLocker lLock( mAccess );
353 int32_t iParent = -1; 366 int32_t iParent = -1;
354 int32_t iNode; 367 int32_t iNode;
355 iNode = lookupInode( sPath, iParent ); 368 iNode = lookupInode( sPath, iParent );
@@ -359,6 +372,7 @@ void Bu::MyriadFs::setFileSize( const Bu::String &sPath, int32_t iSize )
359 372
360void Bu::MyriadFs::rename( const Bu::String &sFrom, const Bu::String &sTo ) 373void Bu::MyriadFs::rename( const Bu::String &sFrom, const Bu::String &sTo )
361{ 374{
375 Bu::MutexLocker lLock( mAccess );
362 mkHardLink( sFrom, sTo ); 376 mkHardLink( sFrom, sTo );
363 unlink( sFrom ); 377 unlink( sFrom );
364} 378}
@@ -449,7 +463,7 @@ void Bu::MyriadFs::readInode( int32_t iNode, RawStat &rs, MyriadStream &rIs )
449 463
450void Bu::MyriadFs::readInode( int32_t iNode, RawStat &rs ) 464void Bu::MyriadFs::readInode( int32_t iNode, RawStat &rs )
451{ 465{
452 MyriadStream ms = mStore.openStream( 2 ); 466 MyriadStream ms = mStore.open( 2, Bu::Myriad::Read );
453 readInode( iNode, rs, ms ); 467 readInode( iNode, rs, ms );
454} 468}
455 469
@@ -464,7 +478,7 @@ void Bu::MyriadFs::writeInode( const RawStat &rs,
464 478
465void Bu::MyriadFs::writeInode( const RawStat &rs ) 479void Bu::MyriadFs::writeInode( const RawStat &rs )
466{ 480{
467 MyriadStream ms = mStore.openStream( 2 ); 481 MyriadStream ms = mStore.open( 2, Bu::Myriad::Write );
468 writeInode( rs, ms ); 482 writeInode( rs, ms );
469} 483}
470 484
@@ -474,9 +488,9 @@ Bu::MyriadFs::Dir Bu::MyriadFs::readDir( int32_t iNode )
474 int32_t iNumChildren = 0; 488 int32_t iNumChildren = 0;
475 ms.read( &iNumChildren, 4 ); 489 ms.read( &iNumChildren, 4 );
476 490
477 Bu::MyriadStream is = mStore.openStream( 2 ); 491 Bu::MyriadStream is = mStore.open( 2, Bu::Myriad::Read );
478 Dir lDir; 492 Dir lDir;
479 sio << "Reading dir " << iNode << ", " << iNumChildren << " entries:" << sio.nl; 493 // sio << "Reading dir " << iNode << ", " << iNumChildren << " entries:" << sio.nl;
480 for( int32_t j = 0; j < iNumChildren; j++ ) 494 for( int32_t j = 0; j < iNumChildren; j++ )
481 { 495 {
482 int32_t iChildNode = 0; 496 int32_t iChildNode = 0;
@@ -485,7 +499,6 @@ Bu::MyriadFs::Dir Bu::MyriadFs::readDir( int32_t iNode )
485 throw Bu::MyriadFsException( 499 throw Bu::MyriadFsException(
486 "Failed to read iChildNode from directory."); 500 "Failed to read iChildNode from directory.");
487 } 501 }
488 Bu::println(" - iNode = %1").arg( iChildNode );
489 Stat s; 502 Stat s;
490 stat( iChildNode, s, is ); 503 stat( iChildNode, s, is );
491 uint8_t uLen; 504 uint8_t uLen;
@@ -494,14 +507,12 @@ Bu::MyriadFs::Dir Bu::MyriadFs::readDir( int32_t iNode )
494 throw Bu::MyriadFsException( 507 throw Bu::MyriadFsException(
495 "Failed to read uLen from directory."); 508 "Failed to read uLen from directory.");
496 } 509 }
497 Bu::println(" - Name bytes = %1").arg( uLen );
498 s.sName.setSize( uLen ); 510 s.sName.setSize( uLen );
499 if( ms.read( s.sName.getStr(), uLen ) < uLen ) 511 if( ms.read( s.sName.getStr(), uLen ) < uLen )
500 { 512 {
501 throw Bu::MyriadFsException( 513 throw Bu::MyriadFsException(
502 "Failed to read sName from directory."); 514 "Failed to read sName from directory.");
503 } 515 }
504 Bu::println(" - Name = \"%1\"").arg( s.sName );
505 lDir.append( s ); 516 lDir.append( s );
506 517
507// sio << " " << s.sName << sio.nl; 518// sio << " " << s.sName << sio.nl;
@@ -519,9 +530,7 @@ Bu::MyriadStream Bu::MyriadFs::openByInode( int32_t iNode )
519 case typeDir: 530 case typeDir:
520 case typeSymLink: 531 case typeSymLink:
521 case typeRegFile: 532 case typeRegFile:
522 Bu::println("Opening stream by iNode=%1, myriad stream=%2") 533 return mStore.open( rs.uStreamIndex, Bu::Myriad::ReadWrite );
523 .arg( iNode ).arg( rs.uStreamIndex );
524 return mStore.openStream( rs.uStreamIndex );
525 534
526 default: 535 default:
527 throw Bu::MyriadFsException( 536 throw Bu::MyriadFsException(
@@ -575,17 +584,17 @@ int32_t Bu::MyriadFs::allocInode( uint16_t uPerms, uint32_t uSpecial )
575 { 584 {
576 case typeRegFile: 585 case typeRegFile:
577 case typeSymLink: 586 case typeSymLink:
578 rs.uStreamIndex = mStore.createStream(); 587 rs.uStreamIndex = mStore.allocate();
579 break; 588 break;
580 589
581 case typeDir: 590 case typeDir:
582 rs.uStreamIndex = mStore.createStream();
583// sio << "Creating directory node, storage: " 591// sio << "Creating directory node, storage: "
584// << rs.uStreamIndex << sio.nl; 592// << rs.uStreamIndex << sio.nl;
585 { 593 {
586 Bu::MyriadStream msDir = mStore.openStream( 594 Bu::MyriadStream msDir = mStore.create(
587 rs.uStreamIndex 595 Bu::Myriad::Write
588 ); 596 );
597 rs.uStreamIndex = msDir.getId();
589 uint32_t uSize = 0; 598 uint32_t uSize = 0;
590 msDir.write( &uSize, 4 ); 599 msDir.write( &uSize, 4 );
591 } 600 }
@@ -631,7 +640,7 @@ void Bu::MyriadFs::stat( int32_t iNode, Stat &rBuf, MyriadStream &rIs )
631 { 640 {
632 case typeRegFile: 641 case typeRegFile:
633 case typeSymLink: 642 case typeSymLink:
634 rBuf.iSize = mStore.getStreamSize( rs.uStreamIndex ); 643 rBuf.iSize = mStore.getSize( rs.uStreamIndex );
635 break; 644 break;
636 645
637 case typeChrDev: 646 case typeChrDev:
@@ -647,7 +656,7 @@ void Bu::MyriadFs::stat( int32_t iNode, Stat &rBuf, MyriadStream &rIs )
647 656
648void Bu::MyriadFs::writeHeader() 657void Bu::MyriadFs::writeHeader()
649{ 658{
650 Bu::MyriadStream ms = mStore.openStream( 1 ); 659 Bu::MyriadStream ms = mStore.open( 1, Bu::Myriad::Write );
651 ms.write( Myriad_Fs_MAGIC_CODE, 4 ); 660 ms.write( Myriad_Fs_MAGIC_CODE, 4 );
652 int8_t iVer = 1; 661 int8_t iVer = 1;
653 int32_t iNumNodes = hNodeIndex.getSize(); 662 int32_t iNumNodes = hNodeIndex.getSize();
@@ -668,7 +677,7 @@ void Bu::MyriadFs::writeHeader()
668void Bu::MyriadFs::setTimes( int32_t iNode, int64_t iATime, int64_t iMTime ) 677void Bu::MyriadFs::setTimes( int32_t iNode, int64_t iATime, int64_t iMTime )
669{ 678{
670 RawStat rs; 679 RawStat rs;
671 Bu::MyriadStream is = mStore.openStream( 2 ); 680 Bu::MyriadStream is = mStore.open( 2, Bu::Myriad::ReadWrite );
672 681
673 readInode( iNode, rs, is ); 682 readInode( iNode, rs, is );
674 rs.iATime = iATime; 683 rs.iATime = iATime;
@@ -681,18 +690,21 @@ void Bu::MyriadFs::destroyNode( int32_t iNode )
681 if( iNode == 0 ) 690 if( iNode == 0 )
682 throw Bu::MyriadFsException("You cannot destroy the root."); 691 throw Bu::MyriadFsException("You cannot destroy the root.");
683 692
684 Bu::MyriadStream is = mStore.openStream( 2 ); 693 uint32_t iPosition;
694 RawStat rsOld;
695
696 Bu::MyriadStream is = mStore.open( 2, Bu::Myriad::ReadWrite );
685 697
686 // This will be overwritten with the last node 698 // This will be overwritten with the last node
687 uint32_t iPosition = hNodeIndex.get( iNode ); 699 iPosition = hNodeIndex.get( iNode );
688 RawStat rsOld;
689 readInode( iNode, rsOld, is ); 700 readInode( iNode, rsOld, is );
701
690 switch( (rsOld.uPerms&typeMask) ) 702 switch( (rsOld.uPerms&typeMask) )
691 { 703 {
692 case typeRegFile: 704 case typeRegFile:
693 case typeDir: 705 case typeDir:
694 case typeSymLink: 706 case typeSymLink:
695 mStore.deleteStream( rsOld.uStreamIndex ); 707 mStore.erase( rsOld.uStreamIndex );
696 break; 708 break;
697 } 709 }
698 710
diff --git a/src/unstable/myriadfs.h b/src/unstable/myriadfs.h
index ff14292..e3008bc 100644
--- a/src/unstable/myriadfs.h
+++ b/src/unstable/myriadfs.h
@@ -11,7 +11,7 @@
11#include <sys/types.h> 11#include <sys/types.h>
12 12
13#include "bu/myriad.h" 13#include "bu/myriad.h"
14#include "bu/readwritemutex.h" 14#include "bu/debugmutex.h"
15 15
16namespace Bu 16namespace Bu
17{ 17{
@@ -108,7 +108,7 @@ namespace Bu
108 Truncate = 0x08, ///< Truncate file if it does exist 108 Truncate = 0x08, ///< Truncate file if it does exist
109 Append = 0x10, ///< Always append on every write 109 Append = 0x10, ///< Always append on every write
110 NonBlock = 0x20, ///< Open file in non-blocking mode 110 NonBlock = 0x20, ///< Open file in non-blocking mode
111 Exclusive = 0x44, ///< Create file, if it exists then fail 111 Exclusive = 0x40, ///< Create file, if it exists then fail
112 112
113 // Helpful mixes 113 // Helpful mixes
114 ReadWrite = 0x03, ///< Open for reading and writing 114 ReadWrite = 0x03, ///< Open for reading and writing
@@ -172,7 +172,13 @@ namespace Bu
172 typedef Bu::Hash<int32_t, int32_t> NodeIndex; 172 typedef Bu::Hash<int32_t, int32_t> NodeIndex;
173 173
174 private: 174 private:
175 /**
176 * Lookup inode.
177 */
175 int32_t lookupInode( const Bu::String &sPath, int32_t &iParent ); 178 int32_t lookupInode( const Bu::String &sPath, int32_t &iParent );
179 /**
180 * Lookup inode.
181 */
176 int32_t lookupInode( Bu::String::const_iterator iStart, 182 int32_t lookupInode( Bu::String::const_iterator iStart,
177 int32_t iNode, int32_t &iParent ); 183 int32_t iNode, int32_t &iParent );
178 void readInode( int32_t iNode, RawStat &rs, MyriadStream &rIs ); 184 void readInode( int32_t iNode, RawStat &rs, MyriadStream &rIs );
@@ -190,12 +196,12 @@ namespace Bu
190 void setTimes( int32_t iNode, int64_t iATime, int64_t iMTime ); 196 void setTimes( int32_t iNode, int64_t iATime, int64_t iMTime );
191 void destroyNode( int32_t iNode ); 197 void destroyNode( int32_t iNode );
192 198
193 Bu::String filePart( const Bu::String &sPath ); 199 static Bu::String filePart( const Bu::String &sPath );
194 200
195 private: 201 private:
196 Bu::Stream &rStore; 202 Bu::Stream &rStore;
197 Bu::Myriad mStore; 203 Bu::Myriad mStore;
198 Bu::ReadWriteMutex mNodeIndex; 204 Bu::DebugMutex mAccess;
199 NodeIndex hNodeIndex; 205 NodeIndex hNodeIndex;
200 int32_t iUser; 206 int32_t iUser;
201 int32_t iGroup; 207 int32_t iGroup;