From 737da9c8687ad93fb00ffeecea7ca0a1426c4667 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 4 Sep 2007 05:09:08 +0200 Subject: [PATCH 01/12] continued wishful thinking in Test form --- src/proc/assetmanager.hpp | 1 - .../components/proc/asset/createassettest.cpp | 56 +++++++++++++++++++ uml/cinelerra3/128133 | 2 +- uml/cinelerra3/130309.diagram | 2 +- uml/cinelerra3/5.session | 9 ++- wiki/renderengine.html | 54 +++++++++++++++--- 6 files changed, 110 insertions(+), 14 deletions(-) diff --git a/src/proc/assetmanager.hpp b/src/proc/assetmanager.hpp index b85113bbb..f63f90e0d 100644 --- a/src/proc/assetmanager.hpp +++ b/src/proc/assetmanager.hpp @@ -40,7 +40,6 @@ namespace proc_interface */ class AssetManager { - int bla; public: /** registers an asset object in the internal DB, providing its unique key */ diff --git a/tests/components/proc/asset/createassettest.cpp b/tests/components/proc/asset/createassettest.cpp index 2fab0a9d3..d08589821 100644 --- a/tests/components/proc/asset/createassettest.cpp +++ b/tests/components/proc/asset/createassettest.cpp @@ -25,6 +25,9 @@ //#include "common/factory.hpp" //#include "common/util.hpp" +#include "proc/assetmanager.hpp" +#include "proc/asset/media.hpp" + //#include #include @@ -49,7 +52,60 @@ namespace asset { virtual void run(Arg arg) { + createMedia(); } + + void createMedia() + { + Category cat(VIDEO,"bin1"); + Asset::Ident key("Name-1", cat, "ichthyo", 5); + P mm1 = asset::Media::create(key,"testfile.mov"); + P mm2 = asset::Media::create(key); + P mm3 = asset::Media::create("testfile2.mov",Category::VIDEO); + + // Assets have been registered and can be retrieved by ID + ASSERT (AssetManager::getAsset (mm1.id) == mm1); + ASSERT (AssetManager::getAsset (mm2.id) == mm2); + ASSERT (AssetManager::getAsset (mm3.id) == mm3); + + ASSERT (AssetManager::getAsset (mm1.id) != mm2); + + PAsset aa1 = AssetManager::getAsset (mm1.id); + ASSERT (aa1 == mm1); + P mX1 = AssetManager::getAsset (mm1.id, Category::VIDEO); + ASSERT (mX1 == mm1); + ASSERT (mX1 == aa1); + try + { // can't be found if the Category is wrong.... + AssetManager::getAsset (mm1.id, Category::AUDIO); + NOTREACHED; + } + catch (cinelerra::error::Invalid) { } + + + // checking the Ident-Fields + ASSERT (mm1->ident.name == "Name-1"); + ASSERT (mm2->ident.name == "Name-1"); + ASSERT (mm3->ident.name == "testfile2"); + + ASSERT (cat == Category (VIDEO,"bin1")); + ASSERT (mm1->ident.category == Category (VIDEO,"bin1")); + ASSERT (mm2->ident.category == Category (VIDEO,"bin1")); + ASSERT (mm3->ident.category == Category (VIDEO,"")); + + ASSERT (mm1->ident.org == "ichthyo"); + ASSERT (mm2->ident.org == "ichthyo"); + ASSERT (mm3->ident.org == "cin3"); + + ASSERT (mm1->ident.version == 5); + ASSERT (mm2->ident.version == 5); + ASSERT (mm3->ident.version == 1); + + ASSERT (mm1->getFilename() == "testfile.mov"); + ASSERT (isnil (mm2.getFilename()); + ASSERT (mm3->getFilename() == "testfile2.mov"); + + } }; diff --git a/uml/cinelerra3/128133 b/uml/cinelerra3/128133 index b457bbab8..8a0a4ec3b 100644 --- a/uml/cinelerra3/128133 +++ b/uml/cinelerra3/128133 @@ -1,6 +1,6 @@ format 40 "AssetManager" // ProcessingLayer::AssetManager - revision 4 + revision 5 modified_by 5 "hiv" // class settings //class diagram settings diff --git a/uml/cinelerra3/130309.diagram b/uml/cinelerra3/130309.diagram index d1300390d..3979c49c4 100644 --- a/uml/cinelerra3/130309.diagram +++ b/uml/cinelerra3/130309.diagram @@ -6,7 +6,7 @@ classcanvas 128005 class_ref 136453 // Asset end classcanvas 128133 class_ref 136581 // AssetManager draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode class drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default - xyz 289 26 2000 + xyz 289 26 2005 end packagecanvas 128517 package_ref 128133 // AssetManager diff --git a/uml/cinelerra3/5.session b/uml/cinelerra3/5.session index b106f468a..f33ed26db 100644 --- a/uml/cinelerra3/5.session +++ b/uml/cinelerra3/5.session @@ -1,14 +1,19 @@ window_sizes 1140 783 270 860 584 120 diagrams active classdiagram_ref 130309 // Asset Kinds - 860 584 100 4 0 0 + 860 584 100 4 60 0 end show_stereotypes selected package_ref 129 // cinelerra3 open + deploymentview_ref 128517 // gen + deploymentview_ref 128645 // gen + deploymentview_ref 128773 // gen + deploymentview_ref 128901 // gen + deploymentview_ref 129029 // gen -package_ref 128005 // design +package_ref 130309 // engine class_ref 136453 // Asset class_ref 136581 // AssetManager class_ref 136709 // Media diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 224f4c324..67e3684f6 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -514,12 +514,13 @@ ColorPalette SiteUrl -
+
Asset management is a subsystem on its own. Assets are "things" that can be loaded into a session, like Media, Clips, Effects, Transitions. It is the "bookkeeping view", while the EDL is the "manipulation and process view". Some Assets can be //loaded// and a collection of Assets is saved with eatch Session. Besides, there is a collection of basic Assets allways available by default.
 
-The Assets are important reference points holding the information needed to access external resources. For example, an Clip asset can reference a Media asset, which in turn holds the external filename from which to get the media stream. For Effects, the situatin is similar. Assets thus serve two quite distinct purposes. One is to load, list, group serarch and browse them, and to provide an entry point to create new or get at existing MObjects in the EDL, while the other purpose is to provide attribute and property informations to the inner parts of the engine, while at the same time isolating and decoupling them from environmental details. 
+The Assets are important reference points holding the information needed to access external resources. For example, an Clip asset can reference a Media asset, which in turn holds the external filename from which to get the media stream. For Effects, the situation is similar. Assets thus serve two quite distinct purposes. One is to load, list, group search and browse them, and to provide an entry point to create new or get at existing MObjects in the EDL, while the other purpose is to provide attribute and property informations to the inner parts of the engine, while at the same time isolating and decoupling them from environmental details. 
 
 We can distinguish several different Kinds of Assets, each one with specific properties. While all these Kinds of Assets implement the basic Asset interface, they themselfs are the __key abstractions__ of the asset management view. Mostly, their interfaces will be used directly, because they are quite different in behaviour. Thus it is common to see asset related operations being templated on the Asset Kind. 
+→ see also [[Creating and registering Assets|AssetCreation]]
 [img[Asset Classess|uml/fig130309.png]]
 
 !Media Asset
@@ -547,9 +548,16 @@ Some additional, virtual facilities created in the course of the editing process
 → MetaAsset {{red{to be defined}}}
 
 !!!!still to be worked out..
-is how to implement the relationship between [[MObject]]s and Assets. Do we use direct pointers, or do we prefer an ID + central registry approach? And how to handle the removal of an Asset (→ see also [[analysis of mem management|ManagementAssetRelation]])
+is how to implement the relationship between [[MObject]]s and Assets. Do we use direct pointers, or do we prefer an ID + central registry approach? And how to handle the removal of an Asset 
+→ see also [[analysis of mem management|ManagementAssetRelation]]
+→ see also [[Creating Objects|ObjectCreation]], especially [[Assets|AssetCreation]]
 
+
+
Assets are created by a Factories returning smart pointers; the Asset creation is bound to specific use cases and //only available// for these specific situations. There is no generic Asset Factory.
+
+For every Asset we generate a __Ident tuple__ and a long ID (hash) derived from this Ident tuple. The constructor of the abstract base class {{{Asset}}} takes care of this step and automatically registeres the new Asset object with the AssetManager. Typically, the factory methods for concrete Asset classes provide some shortcuts providing sensible default values for some of the Ident tuple data fields. They may take additional parameters — for example the factory method for creating {{{asset::Media}}} takes a filename (and may at some point in the future aply "magic" based on examination of the file)
+
Automation is treated as a function over time. It is always tied to a specific Parameter (which can thus be variable over the course of the timeline). All details //how// this function is defined are completely abstracted away. The Parameter uses a ParamProvider to get the value for a given Time (point). Typically, this will use linear or bezier interpolation over a set of keyframes internally. Parameters can be configured to have different value ranges and distribution types (on-off, stepped, continuous, bounded)
 
@@ -940,11 +948,13 @@ For this Cinelerra3 design, we could consider making GOP just another raw media
 →see in [[Wikipedia|http://en.wikipedia.org/wiki/Group_of_pictures]]
 
-
+
This wiki page is the entry point to detail notes covering some technical decisions, details and problems encountered in the course of the implementation of the Cinelerra Renderengine, the Builder and the related parts.
 
 * [[Packages, Interfaces and Namespaces|InterfaceNamespaces]]
 * [[Memory Management Issues|MemoryManagement]]
+* [[Creating and registering Assets|AssetCreation]]
+* [[Creating new Objects|ObjectCreation]]
 
 
@@ -1298,8 +1308,8 @@ From experiences with other middle scale projects, I prefer having the test code * {{red{and what else?}}}
-
-
The MObjects Subsystem contains everything related to the [[EDL]] and the various Media Objects placed within it. Examples for [[MObjects|MObject]] being:
+
+
The ~MObjects Subsystem contains everything related to the [[EDL]] and the various Media Objects placed within. It is complemented by the Asset Management (see → [[Asset]]). Examples for [[MObjects|MObject]] being:
 * audio/video clips
 * effects and plugins
 * special facilities like mask and projector
@@ -1377,6 +1387,27 @@ For the case in question this seems to be the ''resource allocation is construct
 And, last but not least, doing all actual allocations is the job of the backend. Exceptions being long-lived objects, like the Session or the EDL, which are created once and don't bear the danger of causing memory pressure. Besides that, the ProcLayer code shouldn't issue "new" and "delete", rather it should use some central [[Factories]] for all allocation and freeing, so we can redirect these calls down to the backend, which may use pooling or special placement allocators or the like. The rationale is, for modern hardware/architectures, care has to be taken with heap allocations, esp. with many small objects and irregular usage patterns.
 
+
+
We have to consider carefully how to handle the Creation of new class instances. Because, when done naively, it can defeat all efforts of separating subsystems, or — the other extreme — lead to a //switch-on-typeID//  programming style. We strive at a solution somewhere in the middle by utilizing __Abstract Factories__ on Interface or key abstraction classes, but providing specialized overloads for the different use cases. So in each use case we have to decide if we want to create a representant of some general concept (Interface), or if we have a direct colaboration and thus need the Factory to provide
+a more specific sub-Interface or even a concrete type.
+
+!Object creation use cases
+!![[Assets|Asset]]
+|!Action|>|!creates |
+|loading a media file|asset::Media, asset::Codec| |
+|viewing media|asset::Clip| for the whole Media, if not already existant|
+|mark selection as clip|asset::Clip| doesn't add to EDL|
+|loading Plugin|asset::Effect| usually at program startup|
+|create Session|asset::Track, asset::OutPort| |
+→ [[Creating and registering Assets|AssetCreation]]
+
+!![[MObjects|MObject]]
+|add media to EDL|asset::Clip, session::Clip, FixedPlacement| creating whole-media clip on-the-fly |
+|add Clip|session::Clip, FixedPlacement| |
+|attach Effect|session::Effect, RelativePlacement| |
+|start using Automation|session::Auto, asset::Dataset, RelativePlacement| |
+
+
Cinelerra2 introduced OpenGL support for rendering previews. I must admit, I am very unhappy with this, because
 * it just supports some hardware
@@ -1392,8 +1423,9 @@ But because I know the opinions on this topc are varying (users tend to be delig
 My proposed aproach is to treat OpenGL as a separate video raw data type, requiring separete and specialized [[Processing Nodes|ProcNode]] for all calculations. Thus the Builder could connect OpenGL nodes if it is possible to cover the whole render path for preview and fall back to the normal ~ProcNodes for all relevant renders
 
-
-
[img[Block Diagram|uml/fig128005.png]]
+
+
The Cinelerra-3 Processing Layer is comprised of various subsystems and can be separated into a low-level and a high-level part. At the low-level end is the [[Render Engine|OverviewRenderEngine]] which basically is a network of render nodes cooperating closely with the Backend Layer in order to carry out the actual playback and media transforming calculations. Whereas on the high-level side we find several different [[Media Objects|MObjects]] that can be placed into the [[EDL]], edited and manipulated. This is complemented by the [[Asset Management|Asset]], which is the "bookkeeping view" of all the different "things" within each Session.
+[img[Block Diagram|uml/fig128005.png]]
 
@@ -2344,7 +2376,7 @@ Instead, we should try to just connect the various subsystems via Interfaces and * to shield the rendering code of all complexities of thread communication and synchronization, we use the StateProxy
-
+
/*{{{*/
 /* a contrasting background so I can see where one tiddler ends and the other begins */
 body {
@@ -2509,6 +2541,10 @@ h1,h2,h3,h4,h5,h6 {
 	color: #ff2210;
 	padding: 0px 0.8ex;
 }
+
+.viewer th {
+        background: #91a6af;
+}
 /*}}}*/
 
From 39cd8bb121462c40bc682d9486506523546486c3 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 6 Sep 2007 18:16:45 +0200 Subject: [PATCH 02/12] we need the usual README, INSTALL, AUTHORS, and LICENSE file These initial Versions are based on the Cinelerra2 source tree. Feel free to tailor and keeping up-to-date as necessary. --- AUTHORS | 50 +++++++++ COPYING | 340 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ INSTALL | 6 + LICENSE | 17 +++ README | 37 ++++++ 5 files changed, 450 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 INSTALL create mode 100644 LICENSE create mode 100644 README diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..b21a15138 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,50 @@ + +Cinelerra(2) Authors +==================== + +hv=Jack Crossfire +j6t=Johannes Sixt +minmax=Andraz Tori +herman=Herman Robak +baver=Richard Baverstock +pere=Petter Reinholdtsen +tfheen=Tollef Fog Heen +andreask=Andreas Kielb +theraz=Tyler Geddes +dyce=Gergely Erdelyi +dreamlx=David Arendt +ga=Gustavo Iniguez +memenk=Michael Eric Menk +benjif=Benjamin Flaming +cobra=Kevin Brosius +taraba=Mark Taraba +nate=Nathan Kurz +mammique=Camille Harang +kbielefe=Karl Bielefeldt +alexf=Alex Ferrer +pmdumuid=Pierre Dumuid +giskard=Riccardo Setti +jstewart=Joe Stewart +doudou=Sylvain Joyeux +rafael2k=Rafael Diniz +nicolasm=Nicolas Maufrais + +Involved in Design Studies / Prototypes for Cinelerra-3 +======================================================= +cehteh=Christian Thaeter +ichthyo=Hermann Vosseler +plouj=Michael Ploujnikov + +_______________________________________________________________ +Further Credits + +Parts of the Proc-Layer Implementation are heavily inspired by +The Loki Library + Copyright (c) 2001 by Andrei Alexandrescu + Loki is governed by a MIT-License. + See: http://loki-lib.sourceforge.net + and the book: + Alexandrescu, Andrei. + "Modern C++ Design: Generic Programming and Design + Patterns Applied". Copyright (c) 2001. Addison-Wesley. + ISBN 0201704315 diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..eeb586b39 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..c6cf3ff92 --- /dev/null +++ b/INSTALL @@ -0,0 +1,6 @@ +Running / Installing Cinelerra-3 Prototype +========================================== + +** to be written ** + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..b93cee22f --- /dev/null +++ b/LICENSE @@ -0,0 +1,17 @@ +The Cinelerra source code is (C) by the original authors (see AUTHORS) + +======================================================================= +Cinelerra is free software -- you may use and redistribute it under the +Terms and conditions of the GNU GENERAL PUBLIC LICENSE (GPL); +either version 2 of the License, or (at your option) any later version. +======================================================================= +For a copy of the GPL Version 2 see the file "COPYING" + + +In addition to the GPL's warranty stipulation, Cinelerra is distributed WITHOUT +GUARANTEED SUPPORT; without even the guarantee of ADDITIONAL LABOR. Support +that is not guaranteed includes technical support, compiler troubleshooting, +debugging, version matching, updating, among other additional labor which +may or may not be required to meet a user's requirements. + + diff --git a/README b/README new file mode 100644 index 000000000..0ab5fe3ae --- /dev/null +++ b/README @@ -0,0 +1,37 @@ +====================================== +Cinelerra -- the video NLE for Linux +====================================== + + Cinelerra is a nonlinear video editing and compositing tool. + It understands some of the common multimedia formats + (quicktime, avi, ogg) and audio/video compression + codecs (divx, xvid, mpeg1/2/4, ...) + . + It features non-destructive editing, compositing tools, + a selection of effects plugins, processing in RGB, YUV + and RGB-float colormodels and the ability to mix media + with differing sizes and framerates. + +For more information about Cinelerra visit http://cinelerra.org/ + + +------------------------------ +"Cinelerra-3" prototype code +------------------------------ + +**This source tree doesn't contain a working video editing application** +Rather, it contains some design studies and prototype code for improving +some aspects of the Cinelerra Application. This work may eventually +evolve into a new major release of Cinelerra. + +As of 7/2007, we start here with some backend and render engine modules +together with some unit tests. You should find a wiki with detailed +design considerations and developer documentation and a UML model +(usable with BOUML 2.29) in the sibling directories. + + +Build Requirements +------------------ + +*to be written* + From 45ed4b426407d78bc0aaccee4e1eab113859a0a0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 6 Sep 2007 22:13:26 +0200 Subject: [PATCH 03/12] extracted Singleton pattern into a separate Template. I prefer this approach, so I can ignore threadsafety for the moment and add it later just by switching policy --- src/common/cmdline.cpp | 2 +- src/common/singleton.cpp | 102 ++++++++++++++++ src/common/singleton.hpp | 76 ++++++++++++ src/common/singletonpolicies.hpp | 141 ++++++++++++++++++++++ src/common/util.hpp | 14 +++ tests/components/common/singletontest.cpp | 133 ++++++++++++++++++++ tests/components/common/testtargetobj.hpp | 2 +- 7 files changed, 468 insertions(+), 2 deletions(-) create mode 100644 src/common/singleton.cpp create mode 100644 src/common/singleton.hpp create mode 100644 src/common/singletonpolicies.hpp create mode 100644 tests/components/common/singletontest.cpp diff --git a/src/common/cmdline.cpp b/src/common/cmdline.cpp index 4ab1b5131..49b3585ac 100644 --- a/src/common/cmdline.cpp +++ b/src/common/cmdline.cpp @@ -82,4 +82,4 @@ namespace util -} // namespace cinelerra +} // namespace util diff --git a/src/common/singleton.cpp b/src/common/singleton.cpp new file mode 100644 index 000000000..8046504ed --- /dev/null +++ b/src/common/singleton.cpp @@ -0,0 +1,102 @@ +/* + Singleton - template for implementing the singleton pattern + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +==================================================================== +This code is heavily inspired by + The Loki Library (loki-lib/trunk/include/loki/Singleton.h) + Copyright (c) 2001 by Andrei Alexandrescu + This Loki code accompanies the book: + Alexandrescu, Andrei. "Modern C++ Design: + Generic Programming and Design Patterns Applied". + Copyright (c) 2001. Addison-Wesley. ISBN 0201704315 + +* *****************************************************/ + + + +#include "common/singleton.hpp" +#include "common/util.hpp" +#include "nobugcfg.h" + +namespace cinelerra + { + + /** Interface to be used by Singleton's clients. + * Manages internally the instance creation, lifecycle + * and access handling in a multithreaded context. + * @return "the" single instance of class S + */ + template + < class SI, // the class to make Singleton + template class Create, // how to create/destroy the instance + template class Life, // how to manage Singleton Lifecycle + template class Threading + > + SI& + Singleton::instance() + { + if (!pInstance_) + { + ThreadLock guard; + if (!pInstance_) + { + if (isDead_) + { + Life::onDeadReference(); + isDead_ = false; + } + pInstance_ = Create::create(); + Life::scheduleDelete (&destroy); + } } + ENSURE (pInstance_); + ENSURE (!isDead_); + return *pInstance_; + } + + + /** @internal helper used to delegate destroying the single instance + * to the Create policy, at the same time allowing the Life policy + * to control the point in the Application lifecycle when the + * destruction of this instance occures. + */ + template + < class SI, + template class Create, + template class Life, + template class Threading + > + void + Singleton::destroy() + { + REQUIRE (!isDead_); + Create::destroy (pInstance_); + pInstance_ = 0; + isDead_ = true; + } + + + + + namespace singleton + { + + } // namespace singleton + +} // namespace cinelerra diff --git a/src/common/singleton.hpp b/src/common/singleton.hpp new file mode 100644 index 000000000..ce9af67e1 --- /dev/null +++ b/src/common/singleton.hpp @@ -0,0 +1,76 @@ +/* + SINGLETON.hpp - template for implementing the singleton pattern + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +==================================================================== +This code is heavily inspired by + The Loki Library (loki-lib/trunk/include/loki/Singleton.h) + Copyright (c) 2001 by Andrei Alexandrescu + This Loki code accompanies the book: + Alexandrescu, Andrei. "Modern C++ Design: Generic Programming + and Design Patterns Applied". + Copyright (c) 2001. Addison-Wesley. ISBN 0201704315 + +*/ + + + +#ifndef CINELERRA_SINGLETON_H +#define CINELERRA_SINGLETON_H + + +#include "common/singletonpolicies.hpp" ///< several Policies usable together with singleton + + + +namespace cinelerra + { + + /** + * A configurable Template for implementing Singletons + */ + template + < class S, // the class to make Singleton + template class Create = singleton::Static, // how to create/destroy the instance + template class Life = singleton::Automatic, // how to manage Singleton Lifecycle + template class Threading = singleton::IgnoreThreadsafety //TODO use Multithreaded!!! + > + class Singleton + { + public: + static S& instance(); + + private: + typedef Threading::VolatileType SType; + typedef Threading::Lock ThreadLock; + static SType* pInstance_; + static bool isDead_; + + protected: + Singleton () { } + Singleton (const Singleton&) { } + Singleton& operator= (const Singleton&) { return *this; } + + private: + static void destroy(); + }; + + +} // namespace cinelerra +#endif diff --git a/src/common/singletonpolicies.hpp b/src/common/singletonpolicies.hpp new file mode 100644 index 000000000..d4b414b38 --- /dev/null +++ b/src/common/singletonpolicies.hpp @@ -0,0 +1,141 @@ +/* + SINGLETONPOLICIES.hpp - how to manage creation, lifecycle and multithreading + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +==================================================================== +This code is heavily inspired by + The Loki Library (loki-lib/trunk/include/loki/Singleton.h) + Copyright (c) 2001 by Andrei Alexandrescu + This Loki code accompanies the book: + Alexandrescu, Andrei. "Modern C++ Design: Generic Programming + and Design Patterns Applied". + Copyright (c) 2001. Addison-Wesley. ISBN 0201704315 + +*/ + + + +#ifndef CINELERRA_SINGLETON_H +#define CINELERRA_SINGLETON_H + +#include "common/error.hpp" + + + +namespace cinelerra + { + namespace singleton + { + /* == several Policies usable in conjunction with cinelerra::Singleton == */ + + /** + * Policy for creating the Singleton instance statically + */ + template + struct Static + { + static S* create () + { +#ifdef DEBUG + static uint callCount (0); + ASSERT ( 0 == callCount++ ); +#endif + static S _theSingle_; + return &_theSingle_; + } + static void destroy (S*) + { + S->~S(); + } + }; + + + /** + * Policy for creating the Singleton instance heap allocated + */ + template + struct Heap + { + static S* create () { return new S; } + static void destroy (S* pS) { delete pS; } + }; + + + /** + * Policy relying on the compiler/runtime system for Singleton Lifecycle + */ + template + struct Automatic + { + /** implements the Singleton removal by calling + * the provided deleter function at application shutdown, + * relying on the runtime system calling destructors of + * static objects + */ + static void scheduleDelete (void (*deleter) (void)) + { + struct DeleteTrigger + { + ~DeleteTrigger() { *deleter (); } + }; + static DeleteTrigger trigger; + REQUIRE (deleter); + } + + static void onDeadReference () + { + throw error::Logic ("Trying to access the a Singleton instance that has " + "already been released or finished its lifecycle."); + } + }; + + + + /** + * Policy for handling multithreaded access to the singleton instance + * @todo actually implement this policy using the cinelerra databackend. + */ + template + struct Multithreaded + { + typedef volatile S* VolatileType; + class Lock + { + public: + Lock() { UNIMPLEMENTED ("aquire Thread Lock"); } + ~Lock() { UNIMPLEMENTED ("release Thread Lock"); } + }; + }; + + + /** + * Policy just ignoring thread safety + */ + template + struct IgnoreThreadsafety + { + typedef S VolatileType; + struct Lock {}; + }; + + + } // namespace singleton + +} // namespace cinelerra +#endif diff --git a/src/common/util.hpp b/src/common/util.hpp index a9a90e9b0..d66222002 100644 --- a/src/common/util.hpp +++ b/src/common/util.hpp @@ -27,6 +27,8 @@ #include #include +#include "nobugcfg.h" ///////////////////TODO: just temporarily!!!! + namespace util { @@ -80,6 +82,18 @@ namespace util } + + /** produce an identifier based on the given string. + * remove non-standard-chars, reduce punctuation to underscores + */ + string + sanitize (const string& org) + { + UNIMPLEMENTED ("sanitize String"); + return org; ///////////////////////////TODO + } + + } // namespace util /* some common macro definitions */ diff --git a/tests/components/common/singletontest.cpp b/tests/components/common/singletontest.cpp new file mode 100644 index 000000000..a146c9398 --- /dev/null +++ b/tests/components/common/singletontest.cpp @@ -0,0 +1,133 @@ +/* + Singleton(Test) - unittest for our Singleton template + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "common/testtargetobj.hpp" + +#include "common/test/run.hpp" +#include "common/singleton.hpp" +#include "common/util.hpp" +#include "nobugcfg.h" + +#include +#include + +using boost::lexical_cast; +using util::isnil; +using std::string; +using std::cout; + + +namespace cinelerra + { + namespace test + { + + class ObjFactory; + + + /** + * Target object to be instantiated as Singleton + * Allocates a variable amount of additional heap memory + * and prints diagnostic messages. + */ + class TargetObj : public TestTargetObj + { + public: + static int cnt = 0; + static void setCountParam (uint c) { TargetObj::cnt = c; } + protected: + TargetObj () : TestTargetObj(cnt) {} + }; + + + + + + + + + /******************************************************************* + * @test implement a Singleton class using our Singleton Template. + * Expected results: no memory leaks. + * @see cinelerra::Singleton + * @see cinelerra::singleton::Static + * @see cinelerra::singleton::Heap + */ + class Singleton_test : public Test + { + typedef TargetObj& (*InstanceAccessFunc) (void); + InstanceAccessFunc instance; + + virtual void run(Arg arg) + { + uint num= isnil(arg)? 1 : lexical_cast(arg[1]); + TargetObj::setCountParam(num); + + testStaticallyAllocatedSingleton (); + testHeapAllocatedSingleton (); + } + + + /** @test parametrize the Singleton creation such as to create + * the single TargetObj instance as a static variable. + */ + void testStaticallyAllocatedSingleton () + { + instance = &Singleton::instance; + useInstance (); + } + + /** @test parametrize the Singleton creation such as to create + * the single TargetObj instance allocated on the Heap + * and deleted automatically at application shutdown. + */ + void testHeapAllocatedSingleton () + { + instance = &Singleton::instance; + useInstance (); + } + + + + void useInstance () + { + TargetObj& t1 = instance(); + TargetObj& t2 = instance(); + + ASSERT ( &t1 == &t2, "not a Singleton, got two different instances." ); + + cout << "calling a non-static method on the Singleton instance\n" + << string (t1) << "\n"; + } + }; + + + + /** Register this test class... */ + LAUNCHER (Singleton_test, "unit common"); + + + + } // namespace test + +} // namespace cinelerra diff --git a/tests/components/common/testtargetobj.hpp b/tests/components/common/testtargetobj.hpp index 20667cf92..a51ab1ceb 100644 --- a/tests/components/common/testtargetobj.hpp +++ b/tests/components/common/testtargetobj.hpp @@ -46,7 +46,7 @@ namespace cinelerra namespace test { /** - * Target object to be created by the Test-Factory. + * Target object to be created by Test-Factories or as Singleton. * Allocates a variable amount of additional heap memory * and prints diagnostic messages. */ From 79c88c2c87b822d818b570b2c6d73146ce1df0ac Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 7 Sep 2007 23:24:13 +0200 Subject: [PATCH 04/12] outlined Asset and AssetManager interfaces... urrgh. this was rather tough to get right. Main problem is avoiding switch-on-type. --- src/common/singleton.hpp | 4 +- src/common/singletonpolicies.hpp | 20 +- src/common/util.hpp | 27 ++- src/nobugcfg.h | 4 + src/proc/asset.cpp | 94 ++++++-- src/proc/asset.hpp | 201 ++++++++++++++---- src/proc/asset/category.cpp | 24 ++- src/proc/asset/category.hpp | 60 +++++- src/proc/asset/db.hpp | 93 ++++++++ src/proc/assetmanager.cpp | 57 +++-- src/proc/assetmanager.hpp | 73 +++++-- .../common/sanitizedidentifiertest.cpp | 65 ++++++ tests/components/common/singletontest.cpp | 3 +- .../components/proc/asset/createassettest.cpp | 12 +- uml/cinelerra3/128133 | 68 ++++-- uml/cinelerra3/130053 | 41 +++- uml/cinelerra3/130309.diagram | 18 +- uml/cinelerra3/5.session | 9 +- 18 files changed, 738 insertions(+), 135 deletions(-) create mode 100644 src/proc/asset/db.hpp create mode 100644 tests/components/common/sanitizedidentifiertest.cpp diff --git a/src/common/singleton.hpp b/src/common/singleton.hpp index ce9af67e1..6dba2b3a7 100644 --- a/src/common/singleton.hpp +++ b/src/common/singleton.hpp @@ -57,8 +57,8 @@ namespace cinelerra static S& instance(); private: - typedef Threading::VolatileType SType; - typedef Threading::Lock ThreadLock; + typedef typename Threading::VolatileType SType; + typedef typename Threading::Lock ThreadLock; static SType* pInstance_; static bool isDead_; diff --git a/src/common/singletonpolicies.hpp b/src/common/singletonpolicies.hpp index d4b414b38..75a531900 100644 --- a/src/common/singletonpolicies.hpp +++ b/src/common/singletonpolicies.hpp @@ -31,8 +31,8 @@ This code is heavily inspired by -#ifndef CINELERRA_SINGLETON_H -#define CINELERRA_SINGLETON_H +#ifndef CINELERRA_SINGLETONPOLICIES_H +#define CINELERRA_SINGLETONPOLICIES_H #include "common/error.hpp" @@ -59,9 +59,9 @@ namespace cinelerra static S _theSingle_; return &_theSingle_; } - static void destroy (S*) + static void destroy (S* pSi) { - S->~S(); + pSi-> ~S(); } }; @@ -83,19 +83,23 @@ namespace cinelerra template struct Automatic { + typedef void (*DeleterFunc) (void); /** implements the Singleton removal by calling * the provided deleter function at application shutdown, * relying on the runtime system calling destructors of * static objects */ - static void scheduleDelete (void (*deleter) (void)) + static void scheduleDelete (DeleterFunc kill_the_singleton) { struct DeleteTrigger { - ~DeleteTrigger() { *deleter (); } + ~DeleteTrigger() { *del_ (); } + DeleteTrigger(DeleterFunc d) : del_(d) {} + DeleterFunc del_; }; - static DeleteTrigger trigger; - REQUIRE (deleter); + static DeleteTrigger finally(kill_the_singleton); + + REQUIRE (kill_the_singleton); } static void onDeadReference () diff --git a/src/common/util.hpp b/src/common/util.hpp index d66222002..dca8158ee 100644 --- a/src/common/util.hpp +++ b/src/common/util.hpp @@ -38,19 +38,22 @@ namespace util /** a family of util functions providing a "no value whatsoever" test. Works on strings and all STL containers, includes NULL test for pointers */ template - inline bool isnil(const CONT& container) + inline bool + isnil(const CONT& container) { return container.empty(); } template - inline bool isnil(const CONT* pContainer) + inline bool + isnil(const CONT* pContainer) { return !pContainer || pContainer->empty(); } template <> - inline bool isnil(const char* pCStr) + inline bool + isnil(const char* pCStr) { return !pCStr || 0 == std::strlen(pCStr); } @@ -58,14 +61,16 @@ namespace util /** cut a numeric value to be >=0 */ template - inline NUM noneg (NUM val) + inline NUM + noneg (NUM val) { return (0 - inline bool contains (MAP& map, typename MAP::key_type& key) + inline bool + contains (MAP& map, typename MAP::key_type& key) { return map.find(key) != map.end(); } @@ -86,7 +91,7 @@ namespace util /** produce an identifier based on the given string. * remove non-standard-chars, reduce punctuation to underscores */ - string + inline string sanitize (const string& org) { UNIMPLEMENTED ("sanitize String"); @@ -94,6 +99,16 @@ namespace util } + /** convienience shortcut: conversion to c-String via string. + * usable for printf with objects providing to-string conversion. + */ + inline const char* + cStr (const string& org) + { + return org.c_str(); + } + + } // namespace util /* some common macro definitions */ diff --git a/src/nobugcfg.h b/src/nobugcfg.h index fc2ce4622..bca0108b4 100644 --- a/src/nobugcfg.h +++ b/src/nobugcfg.h @@ -50,6 +50,8 @@ /* declare flags used throughout the code base... */ NOBUG_DECLARE_FLAG(config); NOBUG_DECLARE_FLAG(test); + NOBUG_DECLARE_FLAG(assetmem); + NOBUG_DECLARE_FLAG(mobjectmem); #endif /*NOBUGCFG_H ======= (End) Part 1: DECLARATIONS ======== */ @@ -74,6 +76,8 @@ /* flags used throughout the code base... */ NOBUG_CPP_DEFINE_FLAG(config); NOBUG_CPP_DEFINE_FLAG(test); + NOBUG_CPP_DEFINE_FLAG_LIMIT(assetmem, LOG_WARNING); + NOBUG_CPP_DEFINE_FLAG_LIMIT(mobjectmem, LOG_WARNING); #include "common/error.hpp" diff --git a/src/proc/asset.cpp b/src/proc/asset.cpp index 8d51ae61a..06032983e 100644 --- a/src/proc/asset.cpp +++ b/src/proc/asset.cpp @@ -22,48 +22,102 @@ #include "proc/asset.hpp" -#include "proc/asset/category.hpp" +#include "proc/assetmanager.hpp" +#include "common/util.hpp" -namespace proc_interface +#include + + +using boost::format; +using util::cStr; + + +namespace asset { + Asset::Ident::Ident(const string& n, const Category& cat, const string& o, const uint ver) + : name(util::sanitize (n)), + category(cat), org(o), version(ver) + { } + + /** Asset is a Interface class; usually, objects of + * concrete subclasses are created via specialized Factories + */ + Asset::Asset (Ident& idi) + : ident(idi), id(AssetManager::reg (this, idi)) + { } + + Asset::~Asset () throw() + { + TRACE (assetmem, "dtor Asset(id=%d) : %s", size_t(id), cStr(this->ident) ); + } + - /** - * List of entities this asset depends on or requires to be functional. May be empty. The head of this list can be considered the primary prerequisite + Asset::Ident::operator string () const + { + static format id_tuple("(%2%:%3%.%1% v%4%)"); // ignoring threadsafety + return str (id_tuple % name % category % org % version); + } + + + /** List of entities this asset depends on or requires to be functional. + * May be empty. The head of this list can be considered the primary prerequisite */ vector - Asset::getParents () + Asset::getParents () const { + UNIMPLEMENTED ("Asset dependencies."); + } + + + /** All the other assets requiring this asset to be functional. + * For example, all the clips depending on a given media file. + * May be empty. The dependency relation is transitive. + */ + vector + Asset::getDependant () const + { + UNIMPLEMENTED ("Asset dependencies."); } /** - * All the other assets requiring this asset to be functional. For example, all the clips depending on a given media file. May be empty. The dependency relation is transitive. - */ - vector - Asset::getDependant () - { - } - - - /** - * weather this asset is swithced on and consequently included in the fixture and participates in rendering + * weather this asset is swithced on and consequently included + * in the fixture and participates in rendering. */ bool - Asset::isActive () + Asset::isActive () const { + UNIMPLEMENTED ("enable/disable Assets."); } /** - * change the enabled status of this asset. Note the corresponding #isActive predicate may depend on the enablement status of parent assets as well + * change the enablement status of this asset. + * @note the corresponding #isActive predicate may depend + * on the enablement status of parent assets as well. */ void Asset::enable () throw(cinelerra::error::State) { + UNIMPLEMENTED ("enable/disable Assets."); + } + + + /** release all links to other Asset objects held internally. */ + void + Asset::unlink () + { + UNIMPLEMENTED ("deleting Assets."); + } + + /** variant dropping only the links to the given Asset */ + void + Asset::unlink (IDA target) + { + UNIMPLEMENTED ("deleting Assets."); } - - -} // namespace proc_interface + +} // namespace asset diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index e81e8e466..3cceb4859 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -20,61 +20,146 @@ */ +/** @file asset.hpp + ** Proc-Layer Interface: Assets. + ** Declares the Asset top level Interface, the Asset::Ident identification tuple + ** and the asset::ID primary key wrapper. Normally, Assets should be handled + ** using asset::PAsset, a ref counting smart pointer. + ** + ** These classes are placed into namespace asset and proc_interface. + ** + ** @see assetmanager.hpp + */ + #ifndef PROC_INTERFACE_ASSET_H #define PROC_INTERFACE_ASSET_H + +#include "proc/asset/category.hpp" +#include "common/error.hpp" + +#include #include #include #include -#include "common/error.hpp" +#include +#include + using std::string; using std::vector; using std::set; -namespace asset { class Category; } - -namespace proc_interface +namespace asset { - typedef void* PAsset; //////TODO + using std::size_t; + using std::tr1::shared_ptr; - /** - * Superinterface describing especially the bookeeping properties of Assets + + /** + * thin wrapper around a size_t hash ID + * used as primary key for all Asset objects. + * The Templace parameter is intended for tagging + * the ID with type information, causing the + * compiler to select specialized behaviour + * for the different kinds of Assets. + * @see Asset + * @see AssetManager#getID generating ID values + * @see asset::Media */ - class Asset + template + class ID + { + public: + const size_t hash; + ID (size_t id) : hash(id) {} + ID (const KIND& asset) : hash(asset.id) {} + operator size_t() const { return hash; } + }; + + class Asset; + class AssetManager; + typedef const ID& IDA; + + + /** + * Superinterface describing especially bookeeping properties. + * As of 09/2007, there are four Kinds of Assets, each + * comprising a sub-Interface of the Asset Interface: + *
  • asset::Media representing mediafiles
  • + *
  • asset::Proc representing media data processing components (e.g. Effects)
  • + *
  • asset::Struct representing structural components used in the sesion (e.g. Tracks)
  • + *
  • asset::Meta representing meta objects created while editing (e.g. Automation)
  • + *
+ * And of course, there are various concret Asset subclasses, like asset::Clip, + * asset::Effect, asset::Codec, asset::Track, asset::Dataset. + * @note Assets objects have a strict unique identity and because of this are non-copyable. + * You can not create an Asset derived object without registering it with the AssetManager + * automatically. I is possible to copy the PAsset (smart pointer) though. + * + * @since 09/2007 + * @author Ichthyo + */ + class Asset : private boost::noncopyable { public: - /** Asset primary key. */ - const long id; - /** element ID, comprehensible but sanitized. - * The tuple (category, name, org) is unique. + /** + * a POD comprised of all the information + * sufficiently identifying any given Asset. */ - const string name; - - /**primary tree like classification of the asset */ - const asset::Category* category; - - /** origin or authorship id. - * Can be a project abbreviation, a package id or just the authors nickname or UID. - * This allows for the compnent name to be more generic (e.g. "blur"). - * Default for all assets provided by the core cinelerra-3 codebase is "cin3". - */ - const string org; - - /** version number of the thing or concept represented by this asset. - * Of each unique tuple (name, category, org) there will be only one version - * in the whole system. Version 0 is reserved for internal purposes. - * Versions are considered to be ordered, and any higher version is - * supposed to be fully backwards compatible to all previous versions. - */ - const unsigned int version; + struct Ident + { + /** element ID, comprehensible but sanitized. + * The tuple (category, name, org) is unique. + */ + string name; + + /** primary tree like classification of the asset. + * Includes the distinction of different kinds of Assets, + * like Media, Audio, Video, Effects... */ + asset::Category category; + + /** origin or authorship id. + * Can be a project abbreviation, a package id or just the authors nickname or UID. + * This allows for the compnent name to be more generic (e.g. "blur"). + * Default for all assets provided by the core cinelerra-3 codebase is "cin3". + */ + const string org; + + /** version number of the thing or concept represented by this asset. + * Of each unique tuple (name, category, org) there will be only one version + * in the whole system. Version 0 is reserved for internal purposes. + * Versions are considered to be ordered, and any higher version is + * supposed to be fully backwards compatible to all previous versions. + */ + const uint version; + + Ident (const string& n, + const Category& cat, + const string& o, + const uint ver); + + /** @note equality ignores version differences */ + bool operator== (const Ident& other) const + { + return org == other.org + && name == other.name + && category == other.category; + } + + operator string () const; + }; + + const Ident ident; ///< Asset identification tuple + const ID id; ///< Asset primary key. + protected: /** additional classification, selections or departments this asset belongs to. * Groups are optional, non-exclusive and may be overlapping. @@ -88,38 +173,80 @@ namespace proc_interface * perferably "in one line". To be localized. */ const string longDesc; + + + protected: + /** Asset is a Interface class; usually, objects of + * concrete subclasses are created via specialized Factories. + * Calling this base ctor causes registration with AssetManager. + */ + Asset (Ident& idi); + virtual ~Asset() throw() = 0; + + /** release all links to other Asset objects held internally. + * The lifecycle of Asset objects is managed by smart pointers + * and the Asset manager. Calling \c release() breaks interconnectons + * to other Assets in the central Object network comprising the session. + * It is up to the AssetManager to asure the notification of any other + * components that may need to release references to the Asset object + * beeing removed. The rationale is, after releasing all interlinkings, + * when the AssetManager removes its DB entry for this asset, the + * smart pointer goes out of scope and triggers cleanup. + */ + virtual void unlink (); + + /** variant of #unlink() dropping only the links to the given specific + * Asset, leaving all other links intact. Usable for propagating */ + virtual void unlink (IDA target); + + friend class AssetManager; + public: /** List of entities this asset depends on or requires to be functional. * May be empty. The head of this list can be considered the primary prerequisite */ - vector getParents () ; + vector > + getParents () const; /** All the other assets requiring this asset to be functional. * For example, all the clips depending on a given media file. * May be empty. The dependency relation is transitive. */ - vector getDependant () ; + vector > + getDependant () const; /** weather this asset is swithced on and consequently * included in the fixture and participates in rendering */ - bool isActive () ; + bool isActive () const; /** change the enabled status of this asset. * Note the corresponding #isActive predicate may * depend on the enablement status of parent assets as well */ void enable () throw(cinelerra::error::State); + + }; + + + /** shorthand for refcounting Asset pointers */ + typedef shared_ptr PAsset; + + -} // namespace proc_interface +} // namespace asset -namespace asset +namespace proc_interface { - using proc_interface::Asset; + using asset::Asset; + using asset::Category; + using asset::ID; + using asset::IDA; + using asset::PAsset; } #endif diff --git a/src/proc/asset/category.cpp b/src/proc/asset/category.cpp index edd1b85af..520b9d830 100644 --- a/src/proc/asset/category.cpp +++ b/src/proc/asset/category.cpp @@ -22,10 +22,32 @@ #include "proc/asset/category.hpp" +#include "common/util.hpp" +#include "nobugcfg.h" + +using util::isnil; namespace asset { - + + /** human readable representation of the asset::Category. + * @todo to be localized. + */ + Category::operator string () const + { + char *kinds[6] = { "AUDIO" + , "VIDEO" + , "EFFECT" + , "CODEC" + , "STRUCT" + , "META" + }; + REQUIRE ( 0<=kind_ && kind_< 6 ); + string str (kinds[kind_]); + if (!isnil (path_)) + str += "/"+path_; + return str; + } } // namespace asset diff --git a/src/proc/asset/category.hpp b/src/proc/asset/category.hpp index cbf7e0d9f..7df3771d0 100644 --- a/src/proc/asset/category.hpp +++ b/src/proc/asset/category.hpp @@ -24,16 +24,72 @@ #ifndef ASSET_CATEGORY_H #define ASSET_CATEGORY_H +#include +#include +#include + namespace asset { + using std::string; + using std::ostream; + + /** top-level distinction of different Kinds of Assets. + * For convienience, this classification is slightly denormalized, + * as AUDIO, and VIDEO are both asset::Media objects, EFFECT and CODEC + * are asset::Proc objects, while STRUCT and META refer directly to + * the corresponding Interfaces asset::Struct and asset::Meta. + */ + enum Kind + { + AUDIO, + VIDEO, + EFFECT, + CODEC, + STRUCT, + META + }; + /** - * tree like classification of Assets + * Tree like classification of Assets. + * By virtue of the Category, Assets can be organized in nested bins (folders). + * This includes the distinction of different kinds of Assets, like Audio, Video, Effects... + * + * @todo could be far more elaborate. could be a singleton like centralized tree, while + * just holding references to Catetory nodes in the individual Asset. At the moment, + * we use just the most simplistic implementation and handle Category objects + * using value semantics. */ class Category - {}; + { + public: + + private: + Kind kind_; + string path_; + + public: + Category (const Kind root, string subfolder ="") + : kind_(root), path_(subfolder) {}; + + bool operator== (const Category& other) const { return kind_== other.kind_ && path_== other.path_; } + bool operator!= (const Category& other) const { return kind_!= other.kind_ || path_!= other.path_; } + + operator string () const; + + + friend size_t hash_value (const Category& cat) + { + size_t hash = 0; + boost::hash_combine(hash, cat.kind_); + boost::hash_combine(hash, cat.path_); + return hash; + } + + }; + inline ostream& operator<< (ostream& os, const Category& cago) { return os << string(cago); } } // namespace asset diff --git a/src/proc/asset/db.hpp b/src/proc/asset/db.hpp new file mode 100644 index 000000000..55f09a950 --- /dev/null +++ b/src/proc/asset/db.hpp @@ -0,0 +1,93 @@ +/* + DB.hpp - registry holding known Asset instances. + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#ifndef ASSET_DB_H +#define ASSET_DB_H + + +#include "proc/asset.hpp" + +#include +#include + + +namespace asset + { + + + /* ===== hash implementations ===== */ + + size_t + hash_value (const Asset::Ident& idi) + { + size_t hash = 0; + boost::hash_combine(hash, idi.org); + boost::hash_combine(hash, idi.name); + boost::hash_combine(hash, idi.category); + return hash; + } + + size_t + hash_value (const Asset& asset) + { + return asset.id; + } + + + /** + * trivial hash functor. + * returns any hash value unmodified. + * For building a hashtable with keys + * already containing valid hash values. + */ + struct IdentityHash + : public std::unary_function + { + size_t + operator() (size_t val) const { return val; } + }; + + typedef std::tr1::unordered_map IdHashtable; + + + + + /** + * Implementation of the registry holding all Asset + * instances known to the Asset Manager subsystem. + * As of 8/2007 implemented by a hashtable. + */ + class DB : private boost::noncopyable + { + IdHashtable table; + + friend class AssetManager; + + DB () : table() {} + ~DB () {} + + }; + + +} // namespace asset +#endif diff --git a/src/proc/assetmanager.cpp b/src/proc/assetmanager.cpp index 14fc7afff..aa972aab4 100644 --- a/src/proc/assetmanager.cpp +++ b/src/proc/assetmanager.cpp @@ -22,28 +22,57 @@ #include "proc/assetmanager.hpp" +#include "proc/asset/db.hpp" +#include "common/singleton.hpp" -namespace proc_interface +//#include + +using cinelerra::Singleton; + +namespace asset { + + /** get at the system-wide asset manager instance. + * Implemented as singleton. + */ + AssetManager& + AssetManager::instance () + { + return Singleton::instance(); + } + + AssetManager::AssetManager () + : registry (Singleton::instance()) + { } - + + /** provide the unique ID for given Asset::Ident tuple */ + ID + AssetManager::getID (const Asset::Ident& idi) + { + return asset::hash_value (idi); + } + + + /** * registers an asset object in the internal DB, providing its unique key */ - long - AssetManager::reg (string& name, string& category, string& org, uint version) + template + ID + AssetManager::reg (KIND& obj, const Asset::Ident& idi) //throw(cinelerra::error::Invalid) { } - - + + /** * find and return corresponging object */ - template ////TODO: does this work???? - KIND - AssetManager::getAsset (long id) ////throw(cinelerra::Invalid) + template + shared_ptr + AssetManager::getAsset (const ID& id) ////throw(cinelerra::Invalid) { } @@ -52,7 +81,7 @@ namespace proc_interface * @return true if the given id is registered in the internal asset DB */ bool - AssetManager::known (long id) + AssetManager::known (IDA id) { } @@ -61,10 +90,10 @@ namespace proc_interface * remove the given asset together with all its dependants from the internal DB */ void - AssetManager::remove (long id) /////throw(cinelerra::Invalid, cinelerra::State) - { - } + AssetManager::remove (IDA id) /////throw(cinelerra::Invalid, cinelerra::State) + { + } -} // namespace proc_interface +} // namespace asset diff --git a/src/proc/assetmanager.hpp b/src/proc/assetmanager.hpp index f63f90e0d..3e3e74244 100644 --- a/src/proc/assetmanager.hpp +++ b/src/proc/assetmanager.hpp @@ -20,47 +20,88 @@ */ +/** @file assetmanager.hpp + ** Proc-Layer Interface: Asset Lookup and Organization. + ** Declares the AssetManager interface used to access individual + ** Asset instances. + ** + ** These classes are placed into namespace asset and proc_interface. + ** + ** @see asset.hpp + ** @see mobject.hpp + */ + #ifndef PROC_INTERFACE_ASSETMANAGER_H #define PROC_INTERFACE_ASSETMANAGER_H -#include +#include "proc/asset.hpp" #include "common/error.hpp" +#include +#include +#include using std::string; -namespace proc_interface - { +namespace asset + { + + class DB; + + /** * Facade for the Asset subsystem */ - class AssetManager + class AssetManager : private boost::noncopyable { + asset::DB & registry; + + public: - /** registers an asset object in the internal DB, providing its unique key - */ - static long reg (string& name, string& category, string& org, uint version) - ; - // throw(cinelerra::error::Invalid); + static AssetManager& instance(); + + /** provide the unique ID for given Asset::Ident tuple */ + static ID getID (const Asset::Ident&); + /** find and return corresponging object */ template -// void* /////////////////TODO - KIND - getAsset (long id) ;///throw(cinelerra::error::Invalid); + shared_ptr getAsset (const ID& id) ;///throw(cinelerra::error::Invalid); + /** @return true if the given id is registered in the internal asset DB */ - bool known (long id) ; + bool known (IDA id) ; /**remove the given asset from the internal DB. - * together with all its dependants + * together with all its dependants */ + void remove (IDA id) ;///throw(cinelerra::error::Invalid, cinelerra::error::State); + + + protected: + /** registers an asset object in the internal DB, providing its unique key. + * @internal used by the Asset base class ctor to create Asset::id. */ - void remove (long id) ;///throw(cinelerra::error::Invalid, cinelerra::error::State); + template + static ID reg (KIND& obj, const Asset::Ident& idi) + ; + // throw(cinelerra::error::Invalid); + friend Asset::Asset (Asset::Ident& idi); + + AssetManager (); + }; -} // namespace proc_interface +} // namespace asset + + + +namespace proc_interface + { + using asset::AssetManager; +} + #endif diff --git a/tests/components/common/sanitizedidentifiertest.cpp b/tests/components/common/sanitizedidentifiertest.cpp new file mode 100644 index 000000000..709879606 --- /dev/null +++ b/tests/components/common/sanitizedidentifiertest.cpp @@ -0,0 +1,65 @@ +/* + SanitizedIdentifier(Test) - remove non-standard-chars and punctuation + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "nobugcfg.h" + +#include "common/test/run.hpp" +#include "common/util.hpp" + + +#include +using std::cout; + + + +namespace util + { + namespace test + { + + + class SanitizedIdentifier_test : public Test + { + virtual void run (Arg arg) + { + print_clean ("Word"); + print_clean ("a Sentence"); + print_clean ("with a lot \nof Whitespace"); + print_clean ("with\"much (punctuation)!"); + print_clean ("Bääääh!!"); + } + + /** @test print the original and the sanitized string */ + void print_clean (const string& org) + { + cout << "'" << org << "' --> '" << sanitize(org) << "'\n"; + } + }; + + LAUNCHER (SanitizedIdentifier_test, "unit common"); + + + } // namespace test + +} // namespace util + diff --git a/tests/components/common/singletontest.cpp b/tests/components/common/singletontest.cpp index a146c9398..cd42b5917 100644 --- a/tests/components/common/singletontest.cpp +++ b/tests/components/common/singletontest.cpp @@ -53,12 +53,13 @@ namespace cinelerra class TargetObj : public TestTargetObj { public: - static int cnt = 0; + static int cnt; static void setCountParam (uint c) { TargetObj::cnt = c; } protected: TargetObj () : TestTargetObj(cnt) {} }; + int TargetObj::cnt = 0; diff --git a/tests/components/proc/asset/createassettest.cpp b/tests/components/proc/asset/createassettest.cpp index d08589821..2b415222c 100644 --- a/tests/components/proc/asset/createassettest.cpp +++ b/tests/components/proc/asset/createassettest.cpp @@ -41,6 +41,7 @@ namespace asset namespace test { +// typedef Category::Kind Kind; @@ -57,11 +58,12 @@ namespace asset void createMedia() { + typedef shared_ptr PM; Category cat(VIDEO,"bin1"); Asset::Ident key("Name-1", cat, "ichthyo", 5); - P mm1 = asset::Media::create(key,"testfile.mov"); - P mm2 = asset::Media::create(key); - P mm3 = asset::Media::create("testfile2.mov",Category::VIDEO); + PM mm1 = asset::Media::create(key,"testfile.mov"); + PM mm2 = asset::Media::create(key); + PM mm3 = asset::Media::create("testfile2.mov",Category::VIDEO); // Assets have been registered and can be retrieved by ID ASSERT (AssetManager::getAsset (mm1.id) == mm1); @@ -72,7 +74,7 @@ namespace asset PAsset aa1 = AssetManager::getAsset (mm1.id); ASSERT (aa1 == mm1); - P mX1 = AssetManager::getAsset (mm1.id, Category::VIDEO); + PM mX1 = AssetManager::getAsset (mm1.id, Category::VIDEO); ASSERT (mX1 == mm1); ASSERT (mX1 == aa1); try @@ -102,7 +104,7 @@ namespace asset ASSERT (mm3->ident.version == 1); ASSERT (mm1->getFilename() == "testfile.mov"); - ASSERT (isnil (mm2.getFilename()); + ASSERT (isnil (mm2.getFilename())); ASSERT (mm3->getFilename() == "testfile2.mov"); } diff --git a/uml/cinelerra3/128133 b/uml/cinelerra3/128133 index 8a0a4ec3b..61a7035be 100644 --- a/uml/cinelerra3/128133 +++ b/uml/cinelerra3/128133 @@ -1,6 +1,6 @@ format 40 -"AssetManager" // ProcessingLayer::AssetManager - revision 5 +"Asset" // ProcessingLayer::Asset + revision 6 modified_by 5 "hiv" // class settings //class diagram settings @@ -228,18 +228,13 @@ ${members}}; explicit_switch_type "" comment "Facade for the Asset subsystem" - operation 132357 "register" - class_operation public explicit_return_type "long" - nparams 4 - param inout name "name" explicit_type "string" - param inout name "category" explicit_type "string" - param inout name "org" explicit_type "string" - param inout name "uint" explicit_type "version" - nexceptions 1 - explicit_exception "Invalid" - cpp_decl " ${comment}${friend}${static}${inline}${virtual}${type} ${name} ${(}${t0} & ${p0}, ${t1} & ${p1}, ${t2} & ${p2}, ${t3}& ${p3}${)}${const}${volatile} ${throw}${abstract};" + operation 133125 "getID" + class_operation public explicit_return_type "" + nparams 1 + param in name "idi" type class_ref 136453 // Asset + cpp_decl " ${comment}${friend}${static}${inline}${virtual}${type} ${name} ${(}${)}${const}${volatile} ${throw}${abstract};" cpp_def "${comment}${inline}${type} -${class}::${name} ${(}${t0} & ${p0}, ${t1} & ${p1}, ${t2} & ${p2}, ${t3}& ${p3}${)}${const}${volatile} ${throw}${staticnl} +${class}::${name} ${(}${)}${const}${volatile} ${throw}${staticnl} { ${body} } @@ -247,7 +242,6 @@ ${class}::${name} ${(}${t0} & ${p0}, ${t1} & ${p1}, ${t2} & ${p2}, ${t3}& ${p3}$ " - comment "registers an asset object in the internal DB, providing its unique key" end operation 132485 "getAsset" @@ -307,6 +301,38 @@ ${class}::${name} ${(}${t0} ${p0}${)}${const}${volatile} ${throw}${staticnl} comment "remove the given asset together with all its dependants from the internal DB" end + + operation 132357 "reg" + class_operation protected explicit_return_type "long" + nparams 4 + param inout name "name" explicit_type "string" + param inout name "category" explicit_type "string" + param inout name "org" explicit_type "string" + param inout name "uint" explicit_type "version" + nexceptions 1 + explicit_exception "Invalid" + cpp_decl " ${comment}${friend}${static}${inline}${virtual}${type} ${name} ${(}${t0} & ${p0}, ${t1} & ${p1}, ${t2} & ${p2}, ${t3}& ${p3}${)}${const}${volatile} ${throw}${abstract};" + cpp_def "${comment}${inline}${type} +${class}::${name} ${(}${t0} & ${p0}, ${t1} & ${p1}, ${t2} & ${p2}, ${t3}& ${p3}${)}${const}${volatile} ${throw}${staticnl} +{ + ${body} +} + +" + + + comment "registers an asset object in the internal DB, providing its unique key" + end + + classrelation 142085 // registry () + relation 140293 ---> + a role_name "registry" multiplicity "1" protected + comment "@internal Table or DB holding all registered asset instances." + cpp default " ${comment}${static}${mutable}${volatile}${const}${type}* ${name}${value}; +" + classrelation_ref 142085 // registry () + b multiplicity "1" parent class_ref 138373 // DB + end end class 136709 "Media" @@ -585,5 +611,19 @@ ${inlines} b multiplicity "" parent class_ref 137093 // Meta end end + + class 138373 "DB" + visibility package + cpp_decl "${comment}${template}class ${name}${inherit} + { +${members} }; +${inlines} +" + java_decl "" + idl_decl "" + explicit_switch_type "" + + comment "Implementation of the registry holding all Asset instances known to the Asset Manager subsystem. As of 8/2007 implemented by a hashtable." + end end end diff --git a/uml/cinelerra3/130053 b/uml/cinelerra3/130053 index b9cf1d9ad..27985ba52 100644 --- a/uml/cinelerra3/130053 +++ b/uml/cinelerra3/130053 @@ -1,6 +1,6 @@ format 40 "asset" // design::codegen::proc::asset - revision 4 + revision 5 modified_by 5 "hiv" // class settings //class diagram settings @@ -544,5 +544,44 @@ ${namespace_end}" end comment "structural asset holding the configuration of a track in the EDL" end + + artifact 137861 "db" + stereotype "source" + cpp_h "/* + ${NAME}.hpp - ${description} +@{CopyrightClaim}@{GPLHeader} +*/ + + +#ifndef ${NAMESPACE}_${NAME}_H +#define ${NAMESPACE}_${NAME}_H + +${includes} +${declarations} + + +${namespace_start} + +${definition} +${namespace_end} +#endif +" + cpp_src "/* + ${Name} - ${description} +@{CopyrightClaim}@{GPLHeader} +* *****************************************************/ + + +${includes} +${namespace_start} + + +${members} +${namespace_end}" + associated_classes + class_ref 138373 // DB + end + comment "registry holding known Asset instances." + end end end diff --git a/uml/cinelerra3/130309.diagram b/uml/cinelerra3/130309.diagram index 3979c49c4..cf03630ad 100644 --- a/uml/cinelerra3/130309.diagram +++ b/uml/cinelerra3/130309.diagram @@ -6,11 +6,11 @@ classcanvas 128005 class_ref 136453 // Asset end classcanvas 128133 class_ref 136581 // AssetManager draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode class drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default - xyz 289 26 2005 + xyz 290 16 2005 end packagecanvas 128517 - package_ref 128133 // AssetManager - xyzwh 217 182 1994 575 534 + package_ref 128133 // Asset + show_context_mode namespace xyzwh 217 182 1994 575 534 classcanvas 128645 class_ref 136709 // Media draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default xyz 273 347 2005 @@ -63,6 +63,10 @@ classcanvas 132997 class_ref 138245 // Dataset draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default xyz 719 445 2000 end +classcanvas 133253 class_ref 138373 // DB + draw_all_relations default hide_attributes default hide_operations default show_members_full_definition default show_members_visibility default show_members_stereotype default show_parameter_dir default show_parameter_name default package_name_in_tab default class_drawing_mode default drawing_language default show_context_mode default auto_label_position default show_infonote default shadow default + xyz 486 233 2000 + end relationcanvas 129157 relation_ref 138117 // geometry VHV from ref 128645 z 1999 to point 293 315 @@ -127,7 +131,13 @@ relationcanvas 133125 relation_ref 139781 // from ref 132997 z 1999 to ref 129029 no_role_a no_role_b no_multiplicity_a no_multiplicity_b +relationcanvas 133381 relation_ref 140293 // + geometry HV + from ref 128133 z 1999 to point 506 93 + line 133637 z 1999 to ref 133253 + role_a_pos 518 208 3000 no_role_b + multiplicity_a_pos 492 208 3000 multiplicity_b_pos 386 104 3000 line 128261 -_-_ geometry HV - from ref 128005 z 1999 to point 330 150 + from ref 128005 z 1999 to point 331 150 line 128389 z 1999 to ref 128133 end diff --git a/uml/cinelerra3/5.session b/uml/cinelerra3/5.session index f33ed26db..d10b0e4fe 100644 --- a/uml/cinelerra3/5.session +++ b/uml/cinelerra3/5.session @@ -1,11 +1,11 @@ window_sizes 1140 783 270 860 584 120 diagrams active classdiagram_ref 130309 // Asset Kinds - 860 584 100 4 60 0 + 860 584 100 4 0 0 end show_stereotypes selected -package_ref 129 // cinelerra3 + package_ref 129 // cinelerra3 open deploymentview_ref 128517 // gen deploymentview_ref 128645 // gen @@ -13,9 +13,10 @@ open deploymentview_ref 128901 // gen deploymentview_ref 129029 // gen -package_ref 130309 // engine + package_ref 130309 // engine class_ref 136453 // Asset - class_ref 136581 // AssetManager + operation_ref 133125 // getID + operation_ref 132357 // reg class_ref 136709 // Media class_ref 137349 // Clip classview_ref 128005 // Session From 26374ce409a9869102e6f68a594202faf464a754 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 10 Sep 2007 06:45:36 +0200 Subject: [PATCH 05/12] WIP: fleshed out a good deal of the AssetManager foundation. compiles ok, singleton test pass (most of asset creation just commented out...) --- src/common/cmdline.cpp | 13 ++- src/common/singleton.cpp | 102 ----------------- src/common/singleton.hpp | 106 +++++++++++++++--- src/common/singletonpolicies.hpp | 45 +++++--- src/proc/asset.cpp | 4 +- src/proc/asset.hpp | 26 +++-- src/proc/asset/category.hpp | 3 + src/proc/asset/db.hpp | 2 +- src/proc/asset/media.cpp | 93 ++++++++++++++- src/proc/asset/media.hpp | 51 ++++++++- src/proc/asset/preview.hpp | 4 +- src/proc/asset/unknown.hpp | 4 +- src/proc/assetmanager.cpp | 26 ++++- src/proc/assetmanager.hpp | 14 ++- tests/50components.tests | 18 +++ tests/components/common/singletontest.cpp | 32 +++--- .../components/proc/asset/createassettest.cpp | 42 ++++--- uml/cinelerra3/5.session | 34 +++--- 18 files changed, 420 insertions(+), 199 deletions(-) delete mode 100644 src/common/singleton.cpp diff --git a/src/common/cmdline.cpp b/src/common/cmdline.cpp index 49b3585ac..bc553f357 100644 --- a/src/common/cmdline.cpp +++ b/src/common/cmdline.cpp @@ -33,6 +33,13 @@ using boost::algorithm::split; using boost::algorithm::join; using boost::algorithm::is_any_of; using boost::algorithm::token_compress_on; +using boost::regex; +using boost::smatch; +using boost::regex_search; + +using boost::regex; +using boost::smatch; +using boost::regex_search; @@ -59,12 +66,12 @@ namespace util */ Cmdline::Cmdline (const string cmdline) { - boost::regex tokendef("[^ \r\n\t]+"); - boost::smatch match; + regex tokendef("[^ \r\n\t]+"); + smatch match; string::const_iterator it = cmdline.begin(); string::const_iterator end = cmdline.end(); - while (boost::regex_search(it, end, match, tokendef)) + while (regex_search(it, end, match, tokendef)) { string ss(match[0]); this->push_back(ss); diff --git a/src/common/singleton.cpp b/src/common/singleton.cpp deleted file mode 100644 index 8046504ed..000000000 --- a/src/common/singleton.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - Singleton - template for implementing the singleton pattern - - Copyright (C) CinelerraCV - 2007, Christian Thaeter - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -==================================================================== -This code is heavily inspired by - The Loki Library (loki-lib/trunk/include/loki/Singleton.h) - Copyright (c) 2001 by Andrei Alexandrescu - This Loki code accompanies the book: - Alexandrescu, Andrei. "Modern C++ Design: - Generic Programming and Design Patterns Applied". - Copyright (c) 2001. Addison-Wesley. ISBN 0201704315 - -* *****************************************************/ - - - -#include "common/singleton.hpp" -#include "common/util.hpp" -#include "nobugcfg.h" - -namespace cinelerra - { - - /** Interface to be used by Singleton's clients. - * Manages internally the instance creation, lifecycle - * and access handling in a multithreaded context. - * @return "the" single instance of class S - */ - template - < class SI, // the class to make Singleton - template class Create, // how to create/destroy the instance - template class Life, // how to manage Singleton Lifecycle - template class Threading - > - SI& - Singleton::instance() - { - if (!pInstance_) - { - ThreadLock guard; - if (!pInstance_) - { - if (isDead_) - { - Life::onDeadReference(); - isDead_ = false; - } - pInstance_ = Create::create(); - Life::scheduleDelete (&destroy); - } } - ENSURE (pInstance_); - ENSURE (!isDead_); - return *pInstance_; - } - - - /** @internal helper used to delegate destroying the single instance - * to the Create policy, at the same time allowing the Life policy - * to control the point in the Application lifecycle when the - * destruction of this instance occures. - */ - template - < class SI, - template class Create, - template class Life, - template class Threading - > - void - Singleton::destroy() - { - REQUIRE (!isDead_); - Create::destroy (pInstance_); - pInstance_ = 0; - isDead_ = true; - } - - - - - namespace singleton - { - - } // namespace singleton - -} // namespace cinelerra diff --git a/src/common/singleton.hpp b/src/common/singleton.hpp index 6dba2b3a7..9a7e70365 100644 --- a/src/common/singleton.hpp +++ b/src/common/singleton.hpp @@ -37,40 +37,120 @@ This code is heavily inspired by #include "common/singletonpolicies.hpp" ///< several Policies usable together with singleton +#include "common/util.hpp" +#include "nobugcfg.h" + +#include namespace cinelerra { /** - * A configurable Template for implementing Singletons + * A configurable Template for implementing Singletons. + * Actually this is a Functor object, which could be placed into a static field + * of the Singleton (target) class or used directly. + * @note internally uses static fields, so all functor instances share pInstance_ */ template - < class S, // the class to make Singleton + < class SI, // the class to make Singleton template class Create = singleton::Static, // how to create/destroy the instance template class Life = singleton::Automatic, // how to manage Singleton Lifecycle template class Threading = singleton::IgnoreThreadsafety //TODO use Multithreaded!!! > class Singleton { - public: - static S& instance(); - - private: - typedef typename Threading::VolatileType SType; - typedef typename Threading::Lock ThreadLock; + typedef typename Threading::VolatileType SType; + typedef typename Threading::Lock ThreadLock; static SType* pInstance_; static bool isDead_; - protected: - Singleton () { } - Singleton (const Singleton&) { } - Singleton& operator= (const Singleton&) { return *this; } + public: + /** Interface to be used by Singleton's clients. + * Manages internally the instance creation, lifecycle + * and access handling in a multithreaded context. + * @return "the" single instance of class S + */ + SI& operator() () + { + if (!pInstance_) + { + ThreadLock guard; + if (!pInstance_) + { + if (isDead_) + { + Life::onDeadReference(); + isDead_ = false; + } + pInstance_ = Create::create(); + Life::scheduleDelete (&destroy); + } } + ENSURE (pInstance_); + ENSURE (!isDead_); + return *pInstance_; + } private: - static void destroy(); + /** @internal helper used to delegate destroying the single instance + * to the Create policy, at the same time allowing the Life policy + * to control the point in the Application lifecycle when the + * destruction of this instance occures. + */ + static void destroy() + { + REQUIRE (!isDead_); + Create::destroy (pInstance_); + pInstance_ = 0; + isDead_ = true; + } }; + + // Storage for Singleton's static fields... + template + < class SI, + template class C, + template class L, + template class T + > + typename Singleton::SType* + Singleton::pInstance_; + template + < class SI, + template class C, + template class L, + template class T + > + bool Singleton::isDead_; + + + +///// TODO: get rid of the static fields? +///// is tricky because of invoking the destructors. If we rely on instance vars, +///// the object may already have been released when the runtime system calls the +///// destructors of static objects at shutdown. + + /** @internal used to link together the Create policy and Life policy. + * @return a functor object for invoking this->destroy() */ +/* singleton::DelFunc getDeleter() + { + return boost::bind (&Singleton::destroy, + this); + } +*/ + +/* template + class DelFunc + { + typedef void (T::*Fp)(void); + T* t_; + Fp fun_; + public: + DelFunc (T* t, Fp f) : t_(t), fun_(f) {} + void operator() () { (t_->*fun_)(); } + }; +*/ } // namespace cinelerra #endif diff --git a/src/common/singletonpolicies.hpp b/src/common/singletonpolicies.hpp index 75a531900..6cb212660 100644 --- a/src/common/singletonpolicies.hpp +++ b/src/common/singletonpolicies.hpp @@ -36,6 +36,7 @@ This code is heavily inspired by #include "common/error.hpp" +#include namespace cinelerra @@ -56,8 +57,8 @@ namespace cinelerra static uint callCount (0); ASSERT ( 0 == callCount++ ); #endif - static S _theSingle_; - return &_theSingle_; + static char buff[sizeof(S)]; + return new(buff) S(); } static void destroy (S* pSi) { @@ -76,30 +77,46 @@ namespace cinelerra static void destroy (S* pS) { delete pS; } }; - + + + typedef void (*DelFunc)(void); + using std::vector; + /** * Policy relying on the compiler/runtime system for Singleton Lifecycle */ template struct Automatic { - typedef void (*DeleterFunc) (void); /** implements the Singleton removal by calling - * the provided deleter function at application shutdown, - * relying on the runtime system calling destructors of - * static objects + * the provided deleter function(s) at application shutdown, + * relying on the runtime system calling destructors of static + * objects. Because this Policy class can be shared between + * several Singletons, we need to memoize all registered + * deleter functions for calling them at shutdown. */ - static void scheduleDelete (DeleterFunc kill_the_singleton) + static void scheduleDelete (DelFunc kill_the_singleton) { - struct DeleteTrigger + class DeleteTrigger { - ~DeleteTrigger() { *del_ (); } - DeleteTrigger(DeleterFunc d) : del_(d) {} - DeleterFunc del_; + vector dels_; + + public: + void schedule (DelFunc del) + { + dels_.push_back(del); + } + ~DeleteTrigger() + { + vector::iterator i = dels_.begin(); + for ( ; i != dels_.end(); ++i ) + (*i)(); // invoke deleter func + } }; - static DeleteTrigger finally(kill_the_singleton); - + REQUIRE (kill_the_singleton); + static DeleteTrigger finally; + finally.schedule (kill_the_singleton); } static void onDeadReference () diff --git a/src/proc/asset.cpp b/src/proc/asset.cpp index 06032983e..13bda9143 100644 --- a/src/proc/asset.cpp +++ b/src/proc/asset.cpp @@ -44,11 +44,11 @@ namespace asset /** Asset is a Interface class; usually, objects of * concrete subclasses are created via specialized Factories */ - Asset::Asset (Ident& idi) + Asset::Asset (const Ident& idi) : ident(idi), id(AssetManager::reg (this, idi)) { } - Asset::~Asset () throw() + Asset::~Asset () { TRACE (assetmem, "dtor Asset(id=%d) : %s", size_t(id), cStr(this->ident) ); } diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index 3cceb4859..d9bb4f41b 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -76,16 +76,26 @@ namespace asset { public: const size_t hash; - ID (size_t id) : hash(id) {} - ID (const KIND& asset) : hash(asset.id) {} + ID (size_t id) : hash(id) {} + ID (const KIND& asset) : hash(asset.getID()) {} operator size_t() const { return hash; } }; class Asset; class AssetManager; typedef const ID& IDA; + + class Media; + template<> + class ID : public ID + { + public: + ID (size_t id); + ID (const Media&); + }; + /** * Superinterface describing especially bookeeping properties. * As of 09/2007, there are four Kinds of Assets, each @@ -156,7 +166,9 @@ namespace asset operator string () const; }; - const Ident ident; ///< Asset identification tuple + const Ident ident; ///< Asset identification tuple + virtual const ID& getID() const { return id; } + private: const ID id; ///< Asset primary key. @@ -180,8 +192,8 @@ namespace asset * concrete subclasses are created via specialized Factories. * Calling this base ctor causes registration with AssetManager. */ - Asset (Ident& idi); - virtual ~Asset() throw() = 0; + Asset (const Ident& idi); + virtual ~Asset() = 0; /** release all links to other Asset objects held internally. * The lifecycle of Asset objects is managed by smart pointers @@ -244,8 +256,8 @@ namespace proc_interface { using asset::Asset; using asset::Category; - using asset::ID; - using asset::IDA; +// using asset::ID; +// using asset::IDA; using asset::PAsset; } diff --git a/src/proc/asset/category.hpp b/src/proc/asset/category.hpp index 7df3771d0..69137ae1b 100644 --- a/src/proc/asset/category.hpp +++ b/src/proc/asset/category.hpp @@ -75,6 +75,9 @@ namespace asset bool operator== (const Category& other) const { return kind_== other.kind_ && path_== other.path_; } bool operator!= (const Category& other) const { return kind_!= other.kind_ || path_!= other.path_; } + + bool hasKind (Kind refKind) const { return kind_ == refKind; } + operator string () const; diff --git a/src/proc/asset/db.hpp b/src/proc/asset/db.hpp index 55f09a950..1f97ebff5 100644 --- a/src/proc/asset/db.hpp +++ b/src/proc/asset/db.hpp @@ -50,7 +50,7 @@ namespace asset size_t hash_value (const Asset& asset) { - return asset.id; + return asset.getID(); } diff --git a/src/proc/asset/media.cpp b/src/proc/asset/media.cpp index a50360e04..be6cdc070 100644 --- a/src/proc/asset/media.cpp +++ b/src/proc/asset/media.cpp @@ -21,13 +21,104 @@ * *****************************************************/ +#include "proc/assetmanager.hpp" #include "proc/asset/media.hpp" +#include "proc/asset/clip.hpp" +#include "proc/asset/unknown.hpp" +#include "common/util.hpp" +#include "nobugcfg.h" + +#include + +using util::isnil; + +using boost::regex; +using boost::smatch; +using boost::regex_search; + namespace asset { - /** */ + namespace // Implementation details + { + /** helper: extract a name token out of a given path/filename + * @return sanitized token based on the name (minus extension), + * empty string if not the common filename pattern. + */ + string extractName (const string& path) + { + regex pathname_pattern("([^/\\.]+)(\\.\\w+)?$"); + smatch match; + + if (regex_search (path, match, pathname_pattern)) + return util::sanitize (string (match[1])); + else + return ""; + } + } + + MediaFactory Media::create; + + + /** Factory method for Media Asset instances. Depending on the filename given, + * either a asset::Media object or an "Unknown" placeholder will be provided. If + * the given Category already contains an "Unkown", we just get the + * corresponding smart-ptr. Otherwise a new asset::Unknown is created. */ + MediaFactory::PType + MediaFactory::operator() (Asset::Ident& key, const string& file) + { + asset::Media* pM (0); + AssetManager& aMang = AssetManager::instance(); + TODO ("check and fix Category if necessary"); + if (isnil (file)) + { + if (isnil (key.name)) key.name="nil"; + ID id = aMang.getID (key); + if (aMang.known (id)) + return aMang.getAsset(ID(id)); + else + pM = new Unknown(key); + } + else + { + if (isnil (key.name)) key.name=extractName(file); + TODO ("file exists?"); + pM = new Media (key,file); + } + ENSURE (key.category.hasKind (VIDEO) || key.category.hasKind(AUDIO)); + ENSURE (isnil (key.name)); + ENSURE (dynamic_cast(pM) || (isnil (file) && dynamic_cast(pM))); + + return PType (pM, &destroy); + } + + /** Variant of the Factory method for Media Assets, automatically + * providing most of the Asset key fields based on the filename given + */ + MediaFactory::PType + MediaFactory::operator() (const string& file, Category& cat) + { + Asset::Ident key(extractName(file), cat, "cin3", 1); + return MediaFactory::operator() (key, file); + } + + MediaFactory::PType + MediaFactory::operator() (const char* file, Category& cat) + { + if (!file) file = ""; + return operator() (file,cat); + } + + MediaFactory::PType + MediaFactory::operator() (Asset::Ident& key, const char* file) + { + if (!file) file = ""; + return operator() (key,file); + } + + } // namespace asset diff --git a/src/proc/asset/media.hpp b/src/proc/asset/media.hpp index ac0683704..38d6be307 100644 --- a/src/proc/asset/media.hpp +++ b/src/proc/asset/media.hpp @@ -25,21 +25,68 @@ #define ASSET_MEDIA_H #include "proc/asset.hpp" +#include "common/factory.hpp" namespace asset { + + class Media; + class MediaFactory; + + - + /** * key abstraction: media-like assets */ - class Media : public proc_interface::Asset + class Media : public Asset { + string filename_; + public: + virtual const ID& getID() const { return getID(); } + static MediaFactory create; + const string& getFilename () { return filename_; } + + protected: + Media (const Asset::Ident& idi, const string& file) : Asset(idi), filename_(file) {} + friend class MediaFactory; }; + + // definition of ID ctors is possible now, + // after providing full definition of class Media +/* + ID::ID(size_t id) + : ID (id) {}; + + ID::ID(const Media& media) + : ID (media.getID()) {}; + +*/ + + /** + * Factory specialized for createing Media Asset objects. + */ + class MediaFactory : public cinelerra::Factory + { + public: + typedef shared_ptr PType; + + PType operator() (Asset::Ident& key, const string& file=""); + PType operator() (const string& file, Category& cat); + + PType operator() (Asset::Ident& key, const char* file); ///< convienience overload using cString + PType operator() (const char* file, Category& cat); + + protected: + static void destroy (Media* m) { delete m; } + + }; + + } // namespace asset diff --git a/src/proc/asset/preview.hpp b/src/proc/asset/preview.hpp index cec3f6284..689bdc295 100644 --- a/src/proc/asset/preview.hpp +++ b/src/proc/asset/preview.hpp @@ -36,7 +36,9 @@ namespace asset */ class Preview : public Media { - + protected: + Preview (const Asset::Ident& idi) : Media(idi,"") {} + friend class MediaFactory; }; diff --git a/src/proc/asset/unknown.hpp b/src/proc/asset/unknown.hpp index c75cbcab5..189a6438b 100644 --- a/src/proc/asset/unknown.hpp +++ b/src/proc/asset/unknown.hpp @@ -37,7 +37,9 @@ namespace asset */ class Unknown : public Preview { - + protected: + Unknown (const Asset::Ident& idi) : Preview(idi) {} + friend class MediaFactory; }; diff --git a/src/proc/assetmanager.cpp b/src/proc/assetmanager.cpp index aa972aab4..c9ddae933 100644 --- a/src/proc/assetmanager.cpp +++ b/src/proc/assetmanager.cpp @@ -38,11 +38,11 @@ namespace asset AssetManager& AssetManager::instance () { - return Singleton::instance(); + return *(new AssetManager); //////////////////////////////TODO Singleton::instance(); } AssetManager::AssetManager () - : registry (Singleton::instance()) + : registry (*(new DB)) //(Singleton::instance()) { } @@ -62,8 +62,9 @@ namespace asset template ID AssetManager::reg (KIND& obj, const Asset::Ident& idi) - //throw(cinelerra::error::Invalid) + throw(cinelerra::error::Invalid) { + UNIMPLEMENTED ("AssetManager::reg"); } @@ -72,8 +73,10 @@ namespace asset */ template shared_ptr - AssetManager::getAsset (const ID& id) ////throw(cinelerra::Invalid) + AssetManager::getAsset (const ID& id) + throw(cinelerra::error::Invalid) { + UNIMPLEMENTED ("AssetManager::getAsset"); } @@ -83,6 +86,17 @@ namespace asset bool AssetManager::known (IDA id) { + UNIMPLEMENTED ("asset search"); + } + + + /** + * @return true if the given id is registered with the given Category + */ + bool + AssetManager::known (IDA id, const Category& cat) + { + UNIMPLEMENTED ("asset search"); } @@ -90,7 +104,9 @@ namespace asset * remove the given asset together with all its dependants from the internal DB */ void - AssetManager::remove (IDA id) /////throw(cinelerra::Invalid, cinelerra::State) + AssetManager::remove (IDA id) + throw(cinelerra::error::Invalid, + cinelerra::error::State) { } diff --git a/src/proc/assetmanager.hpp b/src/proc/assetmanager.hpp index 3e3e74244..2143fcff5 100644 --- a/src/proc/assetmanager.hpp +++ b/src/proc/assetmanager.hpp @@ -70,15 +70,19 @@ namespace asset /** find and return corresponging object */ template - shared_ptr getAsset (const ID& id) ;///throw(cinelerra::error::Invalid); + shared_ptr getAsset (const ID& id) throw(cinelerra::error::Invalid); /** @return true if the given id is registered in the internal asset DB */ bool known (IDA id) ; + /** @return true if the given id is registered with the given Category */ + bool known (IDA id, const Category& cat) ; + /**remove the given asset from the internal DB. * together with all its dependants */ - void remove (IDA id) ;///throw(cinelerra::error::Invalid, cinelerra::error::State); + void remove (IDA id) throw(cinelerra::error::Invalid, + cinelerra::error::State); protected: @@ -87,9 +91,9 @@ namespace asset */ template static ID reg (KIND& obj, const Asset::Ident& idi) - ; - // throw(cinelerra::error::Invalid); - friend Asset::Asset (Asset::Ident& idi); + throw(cinelerra::error::Invalid); + + friend Asset::Asset (const Asset::Ident& idi); AssetManager (); diff --git a/tests/50components.tests b/tests/50components.tests index 11afe390f..81f64062f 100644 --- a/tests/50components.tests +++ b/tests/50components.tests @@ -133,3 +133,21 @@ out: --> Testgroup=TestGroupID out: --> Test-ID =SingleTestID out: --> remaining=SingleTestID spam --eggs END + + +PLANNED "SanitizedIdentifier_test" SanitizedIdentifier_test < +#include #include using boost::lexical_cast; +using boost::format; using util::isnil; using std::string; using std::cout; @@ -42,8 +44,6 @@ namespace cinelerra namespace test { - class ObjFactory; - /** * Target object to be instantiated as Singleton @@ -57,6 +57,9 @@ namespace cinelerra static void setCountParam (uint c) { TargetObj::cnt = c; } protected: TargetObj () : TestTargetObj(cnt) {} + + friend class singleton::Static; + friend class singleton::Heap; }; int TargetObj::cnt = 0; @@ -76,42 +79,45 @@ namespace cinelerra */ class Singleton_test : public Test { - typedef TargetObj& (*InstanceAccessFunc) (void); + typedef boost::function InstanceAccessFunc; InstanceAccessFunc instance; virtual void run(Arg arg) { uint num= isnil(arg)? 1 : lexical_cast(arg[1]); - TargetObj::setCountParam(num); - testStaticallyAllocatedSingleton (); - testHeapAllocatedSingleton (); + testStaticallyAllocatedSingleton (num++); + testHeapAllocatedSingleton (num++); } /** @test parametrize the Singleton creation such as to create * the single TargetObj instance as a static variable. */ - void testStaticallyAllocatedSingleton () + void testStaticallyAllocatedSingleton (uint num) { - instance = &Singleton::instance; - useInstance (); + Singleton single; + instance = single; + useInstance (num, "statically allocated"); } /** @test parametrize the Singleton creation such as to create * the single TargetObj instance allocated on the Heap * and deleted automatically at application shutdown. */ - void testHeapAllocatedSingleton () + void testHeapAllocatedSingleton (uint num) { - instance = &Singleton::instance; - useInstance (); + Singleton single; + instance = single; + useInstance (num, "heap allocated"); } - void useInstance () + void useInstance (uint num, string kind) { + cout << format("testing TargetObj(%d) as Singleton(%s)\n") % num % kind; + TargetObj::setCountParam(num); TargetObj& t1 = instance(); TargetObj& t2 = instance(); diff --git a/tests/components/proc/asset/createassettest.cpp b/tests/components/proc/asset/createassettest.cpp index 2b415222c..e31dc2ecc 100644 --- a/tests/components/proc/asset/createassettest.cpp +++ b/tests/components/proc/asset/createassettest.cpp @@ -23,14 +23,16 @@ #include "common/test/run.hpp" //#include "common/factory.hpp" -//#include "common/util.hpp" +#include "common/util.hpp" #include "proc/assetmanager.hpp" #include "proc/asset/media.hpp" +#include "proc/asset/proc.hpp" //#include #include +using util::isnil; //using boost::format; using std::string; using std::cout; @@ -58,28 +60,36 @@ namespace asset void createMedia() { - typedef shared_ptr PM; +/* typedef shared_ptr PM; Category cat(VIDEO,"bin1"); Asset::Ident key("Name-1", cat, "ichthyo", 5); PM mm1 = asset::Media::create(key,"testfile.mov"); PM mm2 = asset::Media::create(key); - PM mm3 = asset::Media::create("testfile2.mov",Category::VIDEO); + Category vid(VIDEO);////////////////////////////////////////////////FIXME + PM mm3 = asset::Media::create("testfile2.mov", vid); // Assets have been registered and can be retrieved by ID - ASSERT (AssetManager::getAsset (mm1.id) == mm1); - ASSERT (AssetManager::getAsset (mm2.id) == mm2); - ASSERT (AssetManager::getAsset (mm3.id) == mm3); + AssetManager& aMang = AssetManager::instance(); + ASSERT (aMang.getAsset (mm1->getID()) == mm1); + ASSERT (aMang.getAsset (mm2->getID()) == mm2); + ASSERT (aMang.getAsset (mm3->getID()) == mm3); - ASSERT (AssetManager::getAsset (mm1.id) != mm2); + ASSERT (aMang.getAsset (mm1->getID()) != mm2); - PAsset aa1 = AssetManager::getAsset (mm1.id); - ASSERT (aa1 == mm1); - PM mX1 = AssetManager::getAsset (mm1.id, Category::VIDEO); +// PAsset aa1 = aMang.getAsset (ID(mm1->getID())); // note we get an Asset ref +// ASSERT (aa1 == mm1); + PM mX1 = aMang.getAsset (mm1->getID()); // ..and now we get a Media ref ASSERT (mX1 == mm1); - ASSERT (mX1 == aa1); +// ASSERT (mX1 == aa1); + + ASSERT (aMang.known (mm1->getID())); + ASSERT (aMang.known (mm2->getID())); + ASSERT (aMang.known (mm3->getID())); + + ASSERT ( !aMang.known (mm3->getID(), Category(AUDIO))); // not found within AUDIO-Category try - { // can't be found if the Category is wrong.... - AssetManager::getAsset (mm1.id, Category::AUDIO); + { // can't be found if specifying wrong Asset kind.... +// aMang.getAsset (ID(mm1->getID())); NOTREACHED; } catch (cinelerra::error::Invalid) { } @@ -93,7 +103,7 @@ namespace asset ASSERT (cat == Category (VIDEO,"bin1")); ASSERT (mm1->ident.category == Category (VIDEO,"bin1")); ASSERT (mm2->ident.category == Category (VIDEO,"bin1")); - ASSERT (mm3->ident.category == Category (VIDEO,"")); + ASSERT (mm3->ident.category == Category (VIDEO )); ASSERT (mm1->ident.org == "ichthyo"); ASSERT (mm2->ident.org == "ichthyo"); @@ -104,9 +114,9 @@ namespace asset ASSERT (mm3->ident.version == 1); ASSERT (mm1->getFilename() == "testfile.mov"); - ASSERT (isnil (mm2.getFilename())); + ASSERT (isnil (mm2->getFilename())); ASSERT (mm3->getFilename() == "testfile2.mov"); - +*/ } }; diff --git a/uml/cinelerra3/5.session b/uml/cinelerra3/5.session index d10b0e4fe..d275c7caf 100644 --- a/uml/cinelerra3/5.session +++ b/uml/cinelerra3/5.session @@ -1,26 +1,34 @@ -window_sizes 1140 783 270 860 584 120 +window_sizes 1140 783 270 860 633 71 diagrams - active classdiagram_ref 130309 // Asset Kinds - 860 584 100 4 0 0 + classdiagram_ref 130309 // Asset Kinds + 860 607 100 4 0 0 + classdiagram_ref 130437 // Media-Asset Relations + 688 506 100 4 0 0 + classdiagram_ref 128133 // Session structure + 688 506 100 4 60 0 + classdiagram_ref 128389 // Render Entities + 688 506 100 4 120 0 + objectdiagram_ref 128901 // EDL Example2 + 688 506 100 4 132 0 + objectdiagram_ref 128773 // EDL Example1 + 688 506 100 4 0 0 + active objectdiagram_ref 129029 // Engine Example1 + 860 633 100 4 28 0 end show_stereotypes -selected - package_ref 129 // cinelerra3 +selected objectdiagram_ref 129029 // Engine Example1 open - deploymentview_ref 128517 // gen - deploymentview_ref 128645 // gen - deploymentview_ref 128773 // gen - deploymentview_ref 128901 // gen - deploymentview_ref 129029 // gen - package_ref 130309 // engine +package_ref 128005 // design class_ref 136453 // Asset operation_ref 133125 // getID operation_ref 132357 // reg class_ref 136709 // Media class_ref 137349 // Clip - classview_ref 128005 // Session - classview_ref 128133 // Engine Workings + class_ref 138501 // SpecialWish + +package_ref 128389 // RenderEngine + usecaseview_ref 128005 // Renderengine Use class_ref 135685 // Logic class_ref 135813 // Config class_ref 135941 // State From 814f6fc734b36c328f55391ba1717c19a80f8383 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 12 Sep 2007 06:53:12 +0200 Subject: [PATCH 06/12] CreateAsset_test now passes the compiler, after quite some tinkering.... --- src/proc/asset.hpp | 39 ++++++++++----- src/proc/asset/db.hpp | 3 +- src/proc/asset/media.cpp | 37 ++++++++++++--- src/proc/asset/media.hpp | 47 ++++++++++++++----- src/proc/assetmanager.cpp | 41 ++++++++++++---- src/proc/assetmanager.hpp | 7 ++- .../components/proc/asset/createassettest.cpp | 15 +++--- 7 files changed, 136 insertions(+), 53 deletions(-) diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index d9bb4f41b..fb7fab2e5 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -26,9 +26,28 @@ ** and the asset::ID primary key wrapper. Normally, Assets should be handled ** using asset::PAsset, a ref counting smart pointer. ** - ** These classes are placed into namespace asset and proc_interface. + ** These classes are placed into namespace asset and proc_interface. + ** + ** Assets are handled by a hierarchy of interfaces. Below the top level Asset interface + ** there are interfaces for various different Kinds of Assets, like asset::Media, + ** asset::Proc, etc. Code utilizing the specific properties of e.g. Media assets, will + ** be implemented directly against the asset::Media interface. To make this feasible + ** while at the same time being able to handle all asset Kinds in a uniform manner, + ** we use a hierarchy of ID classes. These IDs are actually just thin wrappers around + ** a hash value, but they carry a template parameter specifying the Asset Kind and the + ** Asset Kind subinterfaces provide a overloaded getID method with a covariant return + ** value. For example the asset::Media#getID returns an ID. By using the + ** templated query function AssetManager#getAsset, we can get at references to the more + ** specific subinterface asset::media just by using the ID value in a typesafe manner. + ** This helps avoiding dynamic typing and switch-on-type, leading to much more robust, + ** extensible and clear code. + ** + ** (Implementation detail: as g++ is not able to handle member function template + ** instantiations completely automatic, we need to trigger some template instantiations + ** at the end of assetmanager.cpp ) ** ** @see assetmanager.hpp + ** @see media.hpp */ @@ -70,6 +89,7 @@ namespace asset * @see Asset * @see AssetManager#getID generating ID values * @see asset::Media + * @see ID */ template class ID @@ -85,16 +105,9 @@ namespace asset class AssetManager; typedef const ID& IDA; - class Media; - template<> - class ID : public ID - { - public: - ID (size_t id); - ID (const Media&); - }; + /** * Superinterface describing especially bookeeping properties. @@ -105,7 +118,7 @@ namespace asset *
  • asset::Struct representing structural components used in the sesion (e.g. Tracks)
  • *
  • asset::Meta representing meta objects created while editing (e.g. Automation)
  • * - * And of course, there are various concret Asset subclasses, like asset::Clip, + * And of course there are various concret Asset subclasses, like asset::Clip, * asset::Effect, asset::Codec, asset::Track, asset::Dataset. * @note Assets objects have a strict unique identity and because of this are non-copyable. * You can not create an Asset derived object without registering it with the AssetManager @@ -168,7 +181,7 @@ namespace asset const Ident ident; ///< Asset identification tuple virtual const ID& getID() const { return id; } - private: + protected: const ID id; ///< Asset primary key. @@ -256,8 +269,8 @@ namespace proc_interface { using asset::Asset; using asset::Category; -// using asset::ID; -// using asset::IDA; + using asset::ID; + using asset::IDA; using asset::PAsset; } diff --git a/src/proc/asset/db.hpp b/src/proc/asset/db.hpp index 1f97ebff5..ea3c41a67 100644 --- a/src/proc/asset/db.hpp +++ b/src/proc/asset/db.hpp @@ -81,11 +81,10 @@ namespace asset { IdHashtable table; - friend class AssetManager; - DB () : table() {} ~DB () {} + friend class cinelerra::singleton::Static; }; diff --git a/src/proc/asset/media.cpp b/src/proc/asset/media.cpp index be6cdc070..180b5b89b 100644 --- a/src/proc/asset/media.cpp +++ b/src/proc/asset/media.cpp @@ -57,20 +57,28 @@ namespace asset return ""; } } + + + + MediaFactory Media::create; ///< storage for the static MediaFactory instance - MediaFactory Media::create; /** Factory method for Media Asset instances. Depending on the filename given, * either a asset::Media object or an "Unknown" placeholder will be provided. If * the given Category already contains an "Unkown", we just get the - * corresponding smart-ptr. Otherwise a new asset::Unknown is created. */ + * corresponding smart-ptr. Otherwise a new asset::Unknown is created. + * @return an Media smart ptr linked to the internally registered smart ptr + * created as a side effect of calling the concrete Media subclass ctor. + */ MediaFactory::PType MediaFactory::operator() (Asset::Ident& key, const string& file) { asset::Media* pM (0); AssetManager& aMang = AssetManager::instance(); + TODO ("check and fix Category if necessary"); + if (isnil (file)) { if (isnil (key.name)) key.name="nil"; @@ -86,11 +94,13 @@ namespace asset TODO ("file exists?"); pM = new Media (key,file); } + ASSERT (pM); ENSURE (key.category.hasKind (VIDEO) || key.category.hasKind(AUDIO)); ENSURE (isnil (key.name)); ENSURE (dynamic_cast(pM) || (isnil (file) && dynamic_cast(pM))); - return PType (pM, &destroy); + return aMang.getAsset (pM->getID()); // note: because we query with an ID, + // we get a Media smart ptr. } @@ -101,7 +111,14 @@ namespace asset MediaFactory::operator() (const string& file, Category& cat) { Asset::Ident key(extractName(file), cat, "cin3", 1); - return MediaFactory::operator() (key, file); + return operator() (key, file); + } + + MediaFactory::PType + MediaFactory::operator() (const string& file, asset::Kind kind) + { + Category cat(kind); + return operator() (file, cat); } @@ -109,16 +126,22 @@ namespace asset MediaFactory::operator() (const char* file, Category& cat) { if (!file) file = ""; - return operator() (file,cat); + return operator() (string(file),cat); + } + + MediaFactory::PType + MediaFactory::operator() (const char* file, asset::Kind kind) + { + if (!file) file = ""; + return operator() (string(file),kind); } MediaFactory::PType MediaFactory::operator() (Asset::Ident& key, const char* file) { if (!file) file = ""; - return operator() (key,file); + return operator() (key, string(file)); } - } // namespace asset diff --git a/src/proc/asset/media.hpp b/src/proc/asset/media.hpp index 38d6be307..4e6507a2a 100644 --- a/src/proc/asset/media.hpp +++ b/src/proc/asset/media.hpp @@ -21,6 +21,17 @@ */ +/** @file media.hpp + ** Media data is a specific Kind of Asset. + ** For the different Kinds of Assets, we use sub-intefaces inheriting + ** from the general Asset interface. To be able to get asset::Media instances + ** directly from the AssetManager, we define a specialization of the Asset ID. + ** + ** @see asset.hpp for explanation + ** @see MediaFactory creating concrete asset::Media instances + ** + */ + #ifndef ASSET_MEDIA_H #define ASSET_MEDIA_H @@ -36,8 +47,16 @@ namespace asset class MediaFactory; + template<> + class ID : public ID + { + public: + ID (size_t id); + ID (const Media&); + }; + /** * key abstraction: media-like assets */ @@ -46,27 +65,29 @@ namespace asset string filename_; public: - virtual const ID& getID() const { return getID(); } static MediaFactory create; - const string& getFilename () { return filename_; } + const string& getFilename () const { return filename_; } + + virtual const ID& getID() const ///< @return ID of kind Media + { + return static_cast& > (Asset::getID()); + } protected: Media (const Asset::Ident& idi, const string& file) : Asset(idi), filename_(file) {} friend class MediaFactory; }; - + // definition of ID ctors is possible now, // after providing full definition of class Media -/* - ID::ID(size_t id) - : ID (id) {}; - - ID::ID(const Media& media) - : ID (media.getID()) {}; -*/ - + inline ID::ID(size_t id) : ID (id) {}; + inline ID::ID(const Media& media) : ID (media.getID()) {}; + + + + /** * Factory specialized for createing Media Asset objects. */ @@ -77,9 +98,11 @@ namespace asset PType operator() (Asset::Ident& key, const string& file=""); PType operator() (const string& file, Category& cat); + PType operator() (const string& file, asset::Kind); - PType operator() (Asset::Ident& key, const char* file); ///< convienience overload using cString + PType operator() (Asset::Ident& key, const char* file); ///< convienience overload using C-String PType operator() (const char* file, Category& cat); + PType operator() (const char* file, asset::Kind); protected: static void destroy (Media* m) { delete m; } diff --git a/src/proc/assetmanager.cpp b/src/proc/assetmanager.cpp index c9ddae933..3a8111fb8 100644 --- a/src/proc/assetmanager.cpp +++ b/src/proc/assetmanager.cpp @@ -23,7 +23,6 @@ #include "proc/assetmanager.hpp" #include "proc/asset/db.hpp" -#include "common/singleton.hpp" //#include @@ -35,14 +34,10 @@ namespace asset /** get at the system-wide asset manager instance. * Implemented as singleton. */ - AssetManager& - AssetManager::instance () - { - return *(new AssetManager); //////////////////////////////TODO Singleton::instance(); - } + Singleton AssetManager::instance; AssetManager::AssetManager () - : registry (*(new DB)) //(Singleton::instance()) + : registry (Singleton() ()) { } @@ -61,7 +56,7 @@ namespace asset */ template ID - AssetManager::reg (KIND& obj, const Asset::Ident& idi) + AssetManager::reg (KIND* obj, const Asset::Ident& idi) throw(cinelerra::error::Invalid) { UNIMPLEMENTED ("AssetManager::reg"); @@ -110,6 +105,32 @@ namespace asset { } - - + +} // namespace asset + + + + + /************************************************************/ + /* explicit template instantiations for various Asset Kinds */ + /************************************************************/ + +#include "proc/asset/media.hpp" +#include "proc/asset/proc.hpp" +#include "proc/asset/struct.hpp" +#include "proc/asset/meta.hpp" + + +namespace asset + { + + template ID AssetManager::reg (Asset* obj, const Asset::Ident& idi); + + + template shared_ptr AssetManager::getAsset (const ID& id) throw(cinelerra::error::Invalid); + template shared_ptr AssetManager::getAsset (const ID& id) throw(cinelerra::error::Invalid); + template shared_ptr AssetManager::getAsset (const ID& id) throw(cinelerra::error::Invalid); + template shared_ptr AssetManager::getAsset (const ID& id) throw(cinelerra::error::Invalid); + template shared_ptr AssetManager::getAsset (const ID& id) throw(cinelerra::error::Invalid); + } // namespace asset diff --git a/src/proc/assetmanager.hpp b/src/proc/assetmanager.hpp index 2143fcff5..d7effe221 100644 --- a/src/proc/assetmanager.hpp +++ b/src/proc/assetmanager.hpp @@ -38,6 +38,7 @@ #include "proc/asset.hpp" #include "common/error.hpp" +#include "common/singleton.hpp" #include #include @@ -62,7 +63,7 @@ namespace asset public: - static AssetManager& instance(); + static cinelerra::Singleton instance; /** provide the unique ID for given Asset::Ident tuple */ static ID getID (const Asset::Ident&); @@ -90,12 +91,14 @@ namespace asset * @internal used by the Asset base class ctor to create Asset::id. */ template - static ID reg (KIND& obj, const Asset::Ident& idi) + static ID reg (KIND* obj, const Asset::Ident& idi) throw(cinelerra::error::Invalid); friend Asset::Asset (const Asset::Ident& idi); AssetManager (); + + friend class cinelerra::singleton::Static; }; diff --git a/tests/components/proc/asset/createassettest.cpp b/tests/components/proc/asset/createassettest.cpp index e31dc2ecc..771c7a568 100644 --- a/tests/components/proc/asset/createassettest.cpp +++ b/tests/components/proc/asset/createassettest.cpp @@ -60,13 +60,12 @@ namespace asset void createMedia() { -/* typedef shared_ptr PM; + typedef shared_ptr PM; Category cat(VIDEO,"bin1"); Asset::Ident key("Name-1", cat, "ichthyo", 5); PM mm1 = asset::Media::create(key,"testfile.mov"); PM mm2 = asset::Media::create(key); - Category vid(VIDEO);////////////////////////////////////////////////FIXME - PM mm3 = asset::Media::create("testfile2.mov", vid); + PM mm3 = asset::Media::create("testfile2.mov", VIDEO); // Assets have been registered and can be retrieved by ID AssetManager& aMang = AssetManager::instance(); @@ -76,11 +75,11 @@ namespace asset ASSERT (aMang.getAsset (mm1->getID()) != mm2); -// PAsset aa1 = aMang.getAsset (ID(mm1->getID())); // note we get an Asset ref -// ASSERT (aa1 == mm1); + PAsset aa1 = aMang.getAsset (ID(mm1->getID())); // note we get an Asset ref + ASSERT (aa1 == mm1); PM mX1 = aMang.getAsset (mm1->getID()); // ..and now we get a Media ref ASSERT (mX1 == mm1); -// ASSERT (mX1 == aa1); + ASSERT (mX1 == aa1); ASSERT (aMang.known (mm1->getID())); ASSERT (aMang.known (mm2->getID())); @@ -89,7 +88,7 @@ namespace asset ASSERT ( !aMang.known (mm3->getID(), Category(AUDIO))); // not found within AUDIO-Category try { // can't be found if specifying wrong Asset kind.... -// aMang.getAsset (ID(mm1->getID())); + aMang.getAsset (ID(mm1->getID())); NOTREACHED; } catch (cinelerra::error::Invalid) { } @@ -116,6 +115,8 @@ namespace asset ASSERT (mm1->getFilename() == "testfile.mov"); ASSERT (isnil (mm2->getFilename())); ASSERT (mm3->getFilename() == "testfile2.mov"); +/* +////////////////////////////////////////////////////////////////////////////////TODO fuck the compiler!!! */ } }; From 9f087bdc9312e4b57f944bff154309fbb8cbbfaa Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 12 Sep 2007 07:27:13 +0200 Subject: [PATCH 07/12] scons: temporarily skipped locking-test, as it doesn't compile (yet) --- tests/SConscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/SConscript b/tests/SConscript index f2dd39dba..1aec1b7b7 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -48,7 +48,7 @@ moduledirs = globRootdirs('*') # # have to treat the plugin-example specially. -isnt_plugin = lambda dir : dir!='plugin' +isnt_plugin = lambda dir : not (dir=='plugin' or dir=='locking') moduledirs = filter(isnt_plugin, moduledirs) pluginExe = treatPluginTestcase(env) From c7466293124aa6590e8591b8a403ac443c44c292 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 14 Sep 2007 19:18:11 +0200 Subject: [PATCH 08/12] util for sanitizing a string, making it usable as identifier --- SConstruct | 2 +- src/common/singleton.hpp | 2 +- src/common/util.cpp | 72 +++++++++++++++++++ src/common/util.hpp | 30 ++++++-- tests/50components.tests | 21 +++++- .../common/sanitizedidentifiertest.cpp | 10 ++- .../common/test/cmdlinewrappertest.cpp | 2 +- 7 files changed, 123 insertions(+), 16 deletions(-) create mode 100644 src/common/util.cpp diff --git a/SConstruct b/SConstruct index b9ac74167..126e40a8d 100644 --- a/SConstruct +++ b/SConstruct @@ -62,7 +62,7 @@ def setupBasicEnvironment(): , BINDIR=BINDIR , CPPPATH=["#"+SRCDIR] # used to find includes, "#" means always absolute to build-root , CPPDEFINES=['-DCINELERRA_VERSION='+VERSION ] # note: it's a list to append further defines - , CCFLAGS='-Wall' + , CCFLAGS='-Wall ' # -fdiagnostics-show-option ) handleNoBugSwitches(env) diff --git a/src/common/singleton.hpp b/src/common/singleton.hpp index 9a7e70365..5c9018f78 100644 --- a/src/common/singleton.hpp +++ b/src/common/singleton.hpp @@ -75,7 +75,7 @@ namespace cinelerra { if (!pInstance_) { - ThreadLock guard; + ThreadLock guard SIDEEFFECT; if (!pInstance_) { if (isDead_) diff --git a/src/common/util.cpp b/src/common/util.cpp new file mode 100644 index 000000000..28958ade9 --- /dev/null +++ b/src/common/util.cpp @@ -0,0 +1,72 @@ +/* + util.cpp - helper functions implementation + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "common/util.hpp" + +#include +#include +#include + +using boost::algorithm::trim_right_copy_if; +using boost::algorithm::is_any_of; +using boost::algorithm::is_alnum; +using boost::algorithm::is_space; + + +namespace util + { + + typedef boost::function ChPredicate; + ChPredicate operator! (ChPredicate p) { return ! boost::bind(p,_1); } + + // character classes used for sanitizing strings + ChPredicate isValid (is_alnum() || is_any_of("-_.:+$'()@")); + ChPredicate isPunct (is_space() || is_any_of(",;#*~´`?\\=/&%![]{}")); + + + string + sanitize (const string& org) + { + string res (trim_right_copy_if(org, !isValid )); + string::iterator j = res.begin(); + string::const_iterator i = org.begin(); + string::const_iterator e = i + (res.length()); + while ( i != e ) + { + while ( i != e && !isValid (*i) ) ++i; + while ( i != e && isValid (*i) ) *(j++) = *(i++); + if ( i != e && isPunct (*i) ) + { + *j++ = '_'; + do ++i; + while ( i != e && isPunct (*i)); + } + } + res.erase(j,res.end()); + return res; + } + + + +} // namespace util + diff --git a/src/common/util.hpp b/src/common/util.hpp index dca8158ee..479142069 100644 --- a/src/common/util.hpp +++ b/src/common/util.hpp @@ -89,14 +89,25 @@ namespace util /** produce an identifier based on the given string. - * remove non-standard-chars, reduce punctuation to underscores + * remove non-standard-chars, reduce sequences of punctuation + * and whitespace to single underscores. The sanitized string + * will start with an alphanumeric character. + * + * @par Example Conversions +\verbatim + "Word" --> 'Word' + "a Sentence" --> 'a_Sentence' + "trailing Withespace \t \n" --> 'trailing_Withespace' + "with a lot \nof Whitespace" --> 'with_a_lot_of_Whitespace' + "with\"much (punctuation)[]!" --> 'withmuch_(punctuation)' + "§&Ω%€ leading garbarge" --> 'leading_garbarge' + "mixed Ω garbarge" --> 'mixed_garbarge' + "Bääääh!!" --> 'Bh' +\endverbatim */ - inline string - sanitize (const string& org) - { - UNIMPLEMENTED ("sanitize String"); - return org; ///////////////////////////TODO - } + string sanitize (const string& org); + + /** convienience shortcut: conversion to c-String via string. @@ -113,6 +124,11 @@ namespace util /* some common macro definitions */ +/** supress "warning: unused variable" on vars, which + * are introduced into a scope because of some sideeffect, i.e. Locking + */ +#define SIDEEFFECT __attribute__ ((unused)); + /** this macro wraps its parameter into a cstring literal */ #define STRINGIFY(TOKEN) __STRNGFY(TOKEN) #define __STRNGFY(TOKEN) #TOKEN diff --git a/tests/50components.tests b/tests/50components.tests index 81f64062f..9b134ed6c 100644 --- a/tests/50components.tests +++ b/tests/50components.tests @@ -41,8 +41,12 @@ out: 2|ä| out: 3|+| out: 4|€| out: -->oo _O()O_ ä + € -out: wrapping cmdline:... -out: --> +out: wrapping cmdline:Ω ooΩ oΩo Ωoo... +out: 0|Ω| +out: 1|ooΩ| +out: 2|oΩo| +out: 3|Ωoo| +out: -->Ω ooΩ oΩo Ωoo out: Standard Cmdlineformat:one two END @@ -135,7 +139,18 @@ out: --> remaining=SingleTestID spam --eggs END -PLANNED "SanitizedIdentifier_test" SanitizedIdentifier_test < 'Word' +out: 'a Sentence' --> 'a_Sentence' +out: 'trailing Withespace +out: ' --> 'trailing_Withespace' +out: 'with a lot +out: of Whitespace' --> 'with_a_lot_of_Whitespace' +out: 'with"much (punctuation)[]!' --> 'withmuch_(punctuation)' +out: '§&Ω%€ leading garbarge' --> 'leading_garbarge' +out: 'mixed Ω garbarge' --> 'mixed_garbarge' +out: 'Bääääh!!' --> 'Bh' +out: '§&Ω%€' --> '' END diff --git a/tests/components/common/sanitizedidentifiertest.cpp b/tests/components/common/sanitizedidentifiertest.cpp index 709879606..938f5cbe4 100644 --- a/tests/components/common/sanitizedidentifiertest.cpp +++ b/tests/components/common/sanitizedidentifiertest.cpp @@ -44,13 +44,17 @@ namespace util { print_clean ("Word"); print_clean ("a Sentence"); - print_clean ("with a lot \nof Whitespace"); - print_clean ("with\"much (punctuation)!"); + print_clean ("trailing Withespace\n \t"); + print_clean ("with a \t lot\n of Whitespace"); + print_clean ("with\"much (punctuation)[]!"); + print_clean ("§&Ω%€ leading garbarge"); + print_clean ("mixed Ω garbarge"); print_clean ("Bääääh!!"); + print_clean ("§&Ω%€"); } /** @test print the original and the sanitized string */ - void print_clean (const string& org) + void print_clean (const string org) { cout << "'" << org << "' --> '" << sanitize(org) << "'\n"; } diff --git a/tests/components/common/test/cmdlinewrappertest.cpp b/tests/components/common/test/cmdlinewrappertest.cpp index 66547535f..5dfaf6af7 100644 --- a/tests/components/common/test/cmdlinewrappertest.cpp +++ b/tests/components/common/test/cmdlinewrappertest.cpp @@ -54,7 +54,7 @@ namespace util testLine("\nspam"); testLine("eat more spam"); testLine(" oo _O()O_ ä + €"); - testLine("\0\too\0\to\0o\t\0oo"); + testLine("Ω\tooΩ\toΩo\tΩoo"); testStandardCmdlineformat(); } From 5da016aa5a4b7f91022170e10d2a4cd5248f9851 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 16 Sep 2007 03:02:05 +0200 Subject: [PATCH 09/12] WIP integration of Asset types and AssetManager --- src/common/multithread.hpp | 54 +++++++++++++++++ src/common/singletonpolicies.hpp | 8 +-- src/common/util.cpp | 6 +- src/proc/asset.hpp | 1 + src/proc/asset/category.cpp | 17 ++++++ src/proc/asset/category.hpp | 3 +- src/proc/asset/db.hpp | 32 +++++++--- src/proc/asset/media.hpp | 3 - src/proc/asset/meta.cpp | 28 ++++++++- src/proc/asset/meta.hpp | 64 +++++++++++++++++++- src/proc/asset/proc.cpp | 28 ++++++++- src/proc/asset/proc.hpp | 61 ++++++++++++++++++- src/proc/asset/struct.cpp | 28 +++++++++ src/proc/asset/struct.hpp | 62 ++++++++++++++++++- src/proc/assetmanager.cpp | 101 ++++++++++++++++++++++++++++--- src/proc/assetmanager.hpp | 10 +++ 16 files changed, 468 insertions(+), 38 deletions(-) create mode 100644 src/common/multithread.hpp diff --git a/src/common/multithread.hpp b/src/common/multithread.hpp new file mode 100644 index 000000000..9451ada05 --- /dev/null +++ b/src/common/multithread.hpp @@ -0,0 +1,54 @@ +/* + MULTITHREAD.hpp - generic interface for multithreading primitives + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + + +#ifndef CINELERRA_MULTITHREAD_H +#define CINELERRA_MULTITHREAD_H + + + +namespace cinelerra + { + + /** + * Interface/Policy for managing parallelism issues. + * Basically everything is forwarded to the corresponding backend functions, + * because managing threads and locking belongs to the cinelerra backend layer. + * + * @todo actually implement this policy using the cinelerra databackend. + */ + struct Thread + { + template + class Lock + { + public: + Lock() { TODO ("aquire Thread Lock for Class"); } + Lock(X*) { TODO ("aquire Thread Lock for Instance"); } + ~Lock() { TODO ("release Thread Lock"); } + }; + }; + + +} // namespace cinelerra +#endif diff --git a/src/common/singletonpolicies.hpp b/src/common/singletonpolicies.hpp index 6cb212660..a5d499c12 100644 --- a/src/common/singletonpolicies.hpp +++ b/src/common/singletonpolicies.hpp @@ -34,6 +34,7 @@ This code is heavily inspired by #ifndef CINELERRA_SINGLETONPOLICIES_H #define CINELERRA_SINGLETONPOLICIES_H +#include "common/multithread.hpp" #include "common/error.hpp" #include @@ -136,12 +137,7 @@ namespace cinelerra struct Multithreaded { typedef volatile S* VolatileType; - class Lock - { - public: - Lock() { UNIMPLEMENTED ("aquire Thread Lock"); } - ~Lock() { UNIMPLEMENTED ("release Thread Lock"); } - }; + typedef cinelerra::Thread::Lock Lock; }; diff --git a/src/common/util.cpp b/src/common/util.cpp index 28958ade9..6adc93ab2 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -39,9 +39,9 @@ namespace util typedef boost::function ChPredicate; ChPredicate operator! (ChPredicate p) { return ! boost::bind(p,_1); } - // character classes used for sanitizing strings - ChPredicate isValid (is_alnum() || is_any_of("-_.:+$'()@")); - ChPredicate isPunct (is_space() || is_any_of(",;#*~´`?\\=/&%![]{}")); + // character classes used for sanitizing a string + ChPredicate isValid (is_alnum() || is_any_of("-_.:+$'()@")); ///< characters to be retained + ChPredicate isPunct (is_space() || is_any_of(",;#*~´`?\\=/&%![]{}")); ///< punctuation to be replaced by '_' string diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index fb7fab2e5..dc20e28ec 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -181,6 +181,7 @@ namespace asset const Ident ident; ///< Asset identification tuple virtual const ID& getID() const { return id; } + protected: const ID id; ///< Asset primary key. diff --git a/src/proc/asset/category.cpp b/src/proc/asset/category.cpp index 520b9d830..2e07c8b3a 100644 --- a/src/proc/asset/category.cpp +++ b/src/proc/asset/category.cpp @@ -25,6 +25,9 @@ #include "common/util.hpp" #include "nobugcfg.h" +#include + +using boost::algorithm::starts_with; using util::isnil; namespace asset @@ -48,6 +51,20 @@ namespace asset str += "/"+path_; return str; } + + + + /** hierarchical inclusion test. + * @return true if \c this can be considered + * a subcategory of the given reference + */ + bool + Category::isWithin (const Category& ref) const + { + return ( ref.hasKind (kind_) + && starts_with (path_, ref.path_) + ); + } } // namespace asset diff --git a/src/proc/asset/category.hpp b/src/proc/asset/category.hpp index 69137ae1b..f27f46845 100644 --- a/src/proc/asset/category.hpp +++ b/src/proc/asset/category.hpp @@ -76,7 +76,8 @@ namespace asset bool operator== (const Category& other) const { return kind_== other.kind_ && path_== other.path_; } bool operator!= (const Category& other) const { return kind_!= other.kind_ || path_!= other.path_; } - bool hasKind (Kind refKind) const { return kind_ == refKind; } + bool hasKind (Kind refKind) const { return kind_ == refKind; } + bool isWithin (const Category&) const; operator string () const; diff --git a/src/proc/asset/db.hpp b/src/proc/asset/db.hpp index ea3c41a67..8ac4207a6 100644 --- a/src/proc/asset/db.hpp +++ b/src/proc/asset/db.hpp @@ -33,7 +33,9 @@ namespace asset { - + using std::tr1::static_pointer_cast; + using std::tr1::dynamic_pointer_cast; + /* ===== hash implementations ===== */ @@ -45,14 +47,14 @@ namespace asset boost::hash_combine(hash, idi.name); boost::hash_combine(hash, idi.category); return hash; - } + } - size_t + size_t hash_value (const Asset& asset) { return asset.getID(); } - + /** * trivial hash functor. @@ -66,12 +68,12 @@ namespace asset size_t operator() (size_t val) const { return val; } }; - + typedef std::tr1::unordered_map IdHashtable; - - - - + + + + /** * Implementation of the registry holding all Asset * instances known to the Asset Manager subsystem. @@ -85,6 +87,18 @@ namespace asset ~DB () {} friend class cinelerra::singleton::Static; + + public: + template + void put (ID hash, shared_ptr& ptr) { table[hash] = static_pointer_cast (ptr); } + void put (ID hash, PAsset& ptr) { table[hash] = ptr; } + + template + shared_ptr + get (ID hash) + { + return dynamic_pointer_cast (table[hash]); + } }; diff --git a/src/proc/asset/media.hpp b/src/proc/asset/media.hpp index 4e6507a2a..cc1a1bdc7 100644 --- a/src/proc/asset/media.hpp +++ b/src/proc/asset/media.hpp @@ -103,9 +103,6 @@ namespace asset PType operator() (Asset::Ident& key, const char* file); ///< convienience overload using C-String PType operator() (const char* file, Category& cat); PType operator() (const char* file, asset::Kind); - - protected: - static void destroy (Media* m) { delete m; } }; diff --git a/src/proc/asset/meta.cpp b/src/proc/asset/meta.cpp index fb0ff7c05..be2382f1f 100644 --- a/src/proc/asset/meta.cpp +++ b/src/proc/asset/meta.cpp @@ -21,13 +21,37 @@ * *****************************************************/ +#include "proc/assetmanager.hpp" #include "proc/asset/meta.hpp" +#include "common/util.hpp" +#include "nobugcfg.h" + namespace asset { - /** */ - + namespace // Implementation details + { + /** helper: .....*/ + } + + MetaFactory Meta::create; ///< storage for the static MetaFactory instance + + + + /** Factory method for Metadata Asset instances. .... + * @todo actually define + * @return an Meta smart ptr linked to the internally registered smart ptr + * created as a side effect of calling the concrete Meta subclass ctor. + */ + MetaFactory::PType + MetaFactory::operator() (Asset::Ident& key) ////TODO + { + UNIMPLEMENTED ("Meta-Factory"); + } + + + } // namespace asset diff --git a/src/proc/asset/meta.hpp b/src/proc/asset/meta.hpp index 4cbd3f9c1..21715fe0f 100644 --- a/src/proc/asset/meta.hpp +++ b/src/proc/asset/meta.hpp @@ -21,26 +21,86 @@ */ +/** @file meta.hpp + ** Some Metatdata elements (e.g. Automation Datasets) can be treated as + ** specific Kind of Asset. + ** For the different Kinds of Assets, we use sub-intefaces inheriting + ** from the general Asset interface. To be able to get asset::Meta instances + ** directly from the AssetManager, we define a specialization of the Asset ID. + ** + ** @see asset.hpp for explanation + ** @see MetaFactory creating concrete asset::Meta instances + ** + */ + #ifndef ASSET_META_H #define ASSET_META_H #include "proc/asset.hpp" +#include "common/factory.hpp" namespace asset { + + class Meta; + class MetaFactory; + + + template<> + class ID : public ID + { + public: + ID (size_t id); + ID (const Meta&); + }; - + + /** * key abstraction: metadata and organisational asset + * @todo just a stub, have to figure out what a asset::Proc is */ - class Meta : public proc_interface::Asset + class Meta : public Asset { + public: + static MetaFactory create; + virtual const ID& getID() const ///< @return ID of kind Meta + { + return static_cast& > (Asset::getID()); + } + + protected: + Meta (const Asset::Ident& idi) : Asset(idi) {} //////////////TODO + friend class MetaFactory; }; + // definition of ID ctors is possible now, + // after providing full definition of class Proc + + inline ID::ID(size_t id) : ID (id) {}; + inline ID::ID(const Meta& meta) : ID (meta.getID()) {}; + + + + + /** + * Factory specialized for createing Metadata Asset objects. + */ + class MetaFactory : public cinelerra::Factory + { + public: + typedef shared_ptr PType; + + PType operator() (Asset::Ident& key); ////////////TODO define actual operation + + }; + + + } // namespace asset #endif diff --git a/src/proc/asset/proc.cpp b/src/proc/asset/proc.cpp index b82ea49d7..7f66edcca 100644 --- a/src/proc/asset/proc.cpp +++ b/src/proc/asset/proc.cpp @@ -21,13 +21,37 @@ * *****************************************************/ +#include "proc/assetmanager.hpp" #include "proc/asset/proc.hpp" +#include "common/util.hpp" +#include "nobugcfg.h" + namespace asset { - /** */ - + namespace // Implementation details + { + /** helper: .....*/ + } + + ProcFactory Proc::create; ///< storage for the static ProcFactory instance + + + + /** Factory method for Processor Asset instances. .... + * @todo actually define + * @return an Proc smart ptr linked to the internally registered smart ptr + * created as a side effect of calling the concrete Proc subclass ctor. + */ + ProcFactory::PType + ProcFactory::operator() (Asset::Ident& key) ////TODO + { + UNIMPLEMENTED ("Proc-Factory"); + } + + + } // namespace asset diff --git a/src/proc/asset/proc.hpp b/src/proc/asset/proc.hpp index 003635b4f..0c201705b 100644 --- a/src/proc/asset/proc.hpp +++ b/src/proc/asset/proc.hpp @@ -21,26 +21,85 @@ */ +/** @file proc.hpp + ** Data processing Plugins and Codecs can be treated as a specific Kind of Asset. + ** For the different Kinds of Assets, we use sub-intefaces inheriting + ** from the general Asset interface. To be able to get asset::Proc instances + ** directly from the AssetManager, we define a specialization of the Asset ID. + ** + ** @see asset.hpp for explanation + ** @see ProcFactory creating concrete asset::Proc instances + ** + */ + #ifndef ASSET_PROC_H #define ASSET_PROC_H #include "proc/asset.hpp" +#include "common/factory.hpp" namespace asset { + + class Proc; + class ProcFactory; + + + template<> + class ID : public ID + { + public: + ID (size_t id); + ID (const Proc&); + }; - + + /** * key abstraction: data processing asset + * @todo just a stub, have to figure out what a asset::Proc is */ class Proc : public Asset { + public: + static ProcFactory create; + virtual const ID& getID() const ///< @return ID of kind Proc + { + return static_cast& > (Asset::getID()); + } + + protected: + Proc (const Asset::Ident& idi) : Asset(idi) {} //////////////TODO + friend class ProcFactory; }; + // definition of ID ctors is possible now, + // after providing full definition of class Proc + + inline ID::ID(size_t id) : ID (id) {}; + inline ID::ID(const Proc& proc) : ID (proc.getID()) {}; + + + + + /** + * Factory specialized for createing Processor Asset objects. + */ + class ProcFactory : public cinelerra::Factory + { + public: + typedef shared_ptr PType; + + PType operator() (Asset::Ident& key); ////////////TODO define actual operation + + }; + + + } // namespace asset #endif diff --git a/src/proc/asset/struct.cpp b/src/proc/asset/struct.cpp index 18769f497..8af2b2e94 100644 --- a/src/proc/asset/struct.cpp +++ b/src/proc/asset/struct.cpp @@ -21,10 +21,38 @@ * *****************************************************/ +#include "proc/assetmanager.hpp" #include "proc/asset/struct.hpp" +#include "common/util.hpp" +#include "nobugcfg.h" namespace asset { + + namespace // Implementation details + { + /** helper: .....*/ + } + + + + StructFactory Struct::create; ///< storage for the static StructFactory instance + + + + /** Factory method for Structural Asset instances. .... + * @todo actually define + * @return an Struct smart ptr linked to the internally registered smart ptr + * created as a side effect of calling the concrete Struct subclass ctor. + */ + StructFactory::PType + StructFactory::operator() (Asset::Ident& key) ////TODO + { + UNIMPLEMENTED ("Struct-Factory"); + } + + + diff --git a/src/proc/asset/struct.hpp b/src/proc/asset/struct.hpp index 787c172dc..dd1b635aa 100644 --- a/src/proc/asset/struct.hpp +++ b/src/proc/asset/struct.hpp @@ -21,23 +21,83 @@ */ +/** @file struct.hpp + ** Structural facilities of the EDL (e.g. Tracks) can be treated in the + ** "bookkeeping view" as a specific Kind of Asset. + ** For the different Kinds of Assets, we use sub-intefaces inheriting + ** from the general Asset interface. To be able to get asset::Struct instances + ** directly from the AssetManager, we define a specialization of the Asset ID. + ** + ** @see asset.hpp for explanation + ** @see StructFactory creating concrete asset::Struct instances + ** + */ + + #ifndef ASSET_STRUCT_H #define ASSET_STRUCT_H #include "proc/asset.hpp" +#include "common/factory.hpp" namespace asset { + + class Struct; + class StructFactory; + + + template<> + class ID : public ID + { + public: + ID (size_t id); + ID (const Struct&); + }; - + + /** * key abstraction: structural asset + * @todo just a stub, have to figure out what a asset::Proc is */ class Struct : public Asset { + public: + static StructFactory create; + virtual const ID& getID() const ///< @return ID of kind asset::Struct + { + return static_cast& > (Asset::getID()); + } + + protected: + Struct (const Asset::Ident& idi) : Asset(idi) {} //////////////TODO + friend class StructFactory; + }; + + + // definition of ID ctors is possible now, + // after providing full definition of class Proc + + inline ID::ID(size_t id) : ID (id) {}; + inline ID::ID(const Struct& stru) : ID (stru.getID()) {}; + + + + + /** + * Factory specialized for createing Structural Asset objects. + */ + class StructFactory : public cinelerra::Factory + { + public: + typedef shared_ptr PType; + + PType operator() (Asset::Ident& key); ////////////TODO define actual operation + }; diff --git a/src/proc/assetmanager.cpp b/src/proc/assetmanager.cpp index 3a8111fb8..0fba91b52 100644 --- a/src/proc/assetmanager.cpp +++ b/src/proc/assetmanager.cpp @@ -24,13 +24,65 @@ #include "proc/assetmanager.hpp" #include "proc/asset/db.hpp" -//#include +#include "common/multithread.hpp" +#include "common/util.hpp" + +#include +#include + +#include +#include + +using boost::format; +using boost::bind; +//using boost::lambda::_1; +using util::for_each; using cinelerra::Singleton; +using cinelerra::Thread; + namespace asset { + /** + * AssetManager error responses, cause by querying + * invalid Asset IDs from the internal DB. + */ + class IDErr : public cinelerra::error::Invalid + { + public: + IDErr (const char* eID, format fmt) + : cinelerra::error::Invalid(fmt.str(),eID) {} + }; + + + // ------pre-defined-common-error-cases--------------- + // + CINELERRA_ERROR_DEFINE (UNKNOWN_ASSET_ID, "non-registered Asset ID"); + CINELERRA_ERROR_DEFINE (WRONG_ASSET_KIND, "wrong Asset kind, unable to cast"); + + class UnknownID : public IDErr + { + public: + UnknownID (ID aID) : IDErr (CINELERRA_ERROR_UNKNOWN_ASSET_ID, + format("Query for Asset with ID=%d, which up to now " + "hasn't been created or encountered.") % aID) {} + }; + + class WrongKind : public IDErr + { + public: + WrongKind (Asset::Ident idi) : IDErr (CINELERRA_ERROR_WRONG_ASSET_KIND, + format("Request for Asset(%s), specifying an Asset kind, " + "that doesn't match the actual type (and can't be " + "casted either).") % string(idi)) {} + }; + + + + + /** get at the system-wide asset manager instance. * Implemented as singleton. */ @@ -52,26 +104,45 @@ namespace asset /** - * registers an asset object in the internal DB, providing its unique key + * registers an asset object in the internal DB, providing its unique key. + * This includes creating the smart ptr in charge of the asset's lifecycle */ template ID AssetManager::reg (KIND* obj, const Asset::Ident& idi) throw(cinelerra::error::Invalid) { - UNIMPLEMENTED ("AssetManager::reg"); + typedef shared_ptr PType; + AssetManager& _aMang (AssetManager::instance()); + TODO ("check validity of Ident Category"); + ID asset_id (getID (idi)); + + Thread::Lock guard SIDEEFFECT; + TODO ("handle duplicate Registrations"); + PType smart_ptr (obj, &destroy); + + _aMang.registry.put (asset_id, smart_ptr); + return asset_id; } /** - * find and return corresponging object + * find and return the object registered with the given ID. + * @throws Invalid if nothing is found or if the actual KIND + * of the stored object differs and can't be casted. */ template shared_ptr AssetManager::getAsset (const ID& id) throw(cinelerra::error::Invalid) { - UNIMPLEMENTED ("AssetManager::getAsset"); + if (shared_ptr obj = registry.get (id)) + return obj; + else + if (known (id)) // provide Ident tuple of existing Asset + throw WrongKind (registry.get(ID(id))->ident); + else + throw UnknownID (id); } @@ -81,8 +152,9 @@ namespace asset bool AssetManager::known (IDA id) { - UNIMPLEMENTED ("asset search"); - } + return ( registry.get (ID(id)) ); + } // query most general Asset ID-kind and use implicit + // conversion from shared_ptr to bool (test if empty) /** @@ -91,9 +163,16 @@ namespace asset bool AssetManager::known (IDA id, const Category& cat) { - UNIMPLEMENTED ("asset search"); + PAsset pA = registry.get (id); + return ( pA && pA->ident.category.isWithin(cat)); } + + void + AssetManager::detach_child (PAsset& pA, IDA id) + { + pA->unlink(id); + } /** * remove the given asset together with all its dependants from the internal DB @@ -103,6 +182,12 @@ namespace asset throw(cinelerra::error::Invalid, cinelerra::error::State) { + UNIMPLEMENTED ("remove Asset with all dependecies"); + + PAsset pA = getAsset (id); + vector par = pA->getParents(); + boost::function func = bind(&detach_child, _1,id ); + for_each (par, func); // ,boost::lambda::var(id))); } diff --git a/src/proc/assetmanager.hpp b/src/proc/assetmanager.hpp index d7effe221..9055c13f8 100644 --- a/src/proc/assetmanager.hpp +++ b/src/proc/assetmanager.hpp @@ -40,6 +40,7 @@ #include "common/error.hpp" #include "common/singleton.hpp" + #include #include #include @@ -94,13 +95,22 @@ namespace asset static ID reg (KIND* obj, const Asset::Ident& idi) throw(cinelerra::error::Invalid); + /** deleter function used by the Asset smart pointers to delet Asset objects */ + static void destroy (Asset* m) { delete m; } + friend Asset::Asset (const Asset::Ident& idi); AssetManager (); friend class cinelerra::singleton::Static; + private: + static void detach_child (PAsset&, IDA); }; + + + CINELERRA_ERROR_DECLARE (UNKNOWN_ASSET_ID); ///< use of a non-registered Asset ID. + CINELERRA_ERROR_DECLARE (WRONG_ASSET_KIND); ///< Asset ID of wrong Asset kind, unable to cast. } // namespace asset From 3a416f9e41f5658a8467f493bc31c56eb5f713bd Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 16 Sep 2007 17:17:54 +0200 Subject: [PATCH 10/12] WIP test coverage, debugging... still have to fix a segfault :-) --- src/proc/asset.cpp | 7 ++ src/proc/asset.hpp | 10 ++ src/proc/asset/media.cpp | 6 +- src/proc/asset/media.hpp | 4 +- src/proc/assetmanager.hpp | 3 +- .../components/proc/asset/createassettest.cpp | 95 ++++++++++++--- .../proc/asset/identityofassetstest.cpp | 110 ++++++++++++++++++ 7 files changed, 214 insertions(+), 21 deletions(-) create mode 100644 tests/components/proc/asset/identityofassetstest.cpp diff --git a/src/proc/asset.cpp b/src/proc/asset.cpp index 13bda9143..0e790becb 100644 --- a/src/proc/asset.cpp +++ b/src/proc/asset.cpp @@ -59,6 +59,13 @@ namespace asset static format id_tuple("(%2%:%3%.%1% v%4%)"); // ignoring threadsafety return str (id_tuple % name % category % org % version); } + + + Asset::operator string () const + { + static format id_tuple("Asset(%2%:%3%.%1% v%4%)"); // ignoring threadsafety + return str (id_tuple % ident.name % ident.category % ident.org % ident.version); + } /** List of entities this asset depends on or requires to be functional. diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index dc20e28ec..d36ab85f2 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -181,6 +181,7 @@ namespace asset const Ident ident; ///< Asset identification tuple virtual const ID& getID() const { return id; } + virtual operator string () const; protected: const ID id; ///< Asset primary key. @@ -260,6 +261,15 @@ namespace asset /** shorthand for refcounting Asset pointers */ typedef shared_ptr PAsset; + /** convienient for debugging */ + inline string str (const PAsset& a) + { + if (a) + return string (*a.get()); + else + return "Asset(NULL)"; + } + } // namespace asset diff --git a/src/proc/asset/media.cpp b/src/proc/asset/media.cpp index 180b5b89b..437b30998 100644 --- a/src/proc/asset/media.cpp +++ b/src/proc/asset/media.cpp @@ -96,7 +96,7 @@ namespace asset } ASSERT (pM); ENSURE (key.category.hasKind (VIDEO) || key.category.hasKind(AUDIO)); - ENSURE (isnil (key.name)); + ENSURE (!isnil (key.name)); ENSURE (dynamic_cast(pM) || (isnil (file) && dynamic_cast(pM))); return aMang.getAsset (pM->getID()); // note: because we query with an ID, @@ -108,7 +108,7 @@ namespace asset * providing most of the Asset key fields based on the filename given */ MediaFactory::PType - MediaFactory::operator() (const string& file, Category& cat) + MediaFactory::operator() (const string& file, const Category& cat) { Asset::Ident key(extractName(file), cat, "cin3", 1); return operator() (key, file); @@ -123,7 +123,7 @@ namespace asset MediaFactory::PType - MediaFactory::operator() (const char* file, Category& cat) + MediaFactory::operator() (const char* file, const Category& cat) { if (!file) file = ""; return operator() (string(file),cat); diff --git a/src/proc/asset/media.hpp b/src/proc/asset/media.hpp index cc1a1bdc7..350ba86f2 100644 --- a/src/proc/asset/media.hpp +++ b/src/proc/asset/media.hpp @@ -97,11 +97,11 @@ namespace asset typedef shared_ptr PType; PType operator() (Asset::Ident& key, const string& file=""); - PType operator() (const string& file, Category& cat); + PType operator() (const string& file, const Category& cat); PType operator() (const string& file, asset::Kind); PType operator() (Asset::Ident& key, const char* file); ///< convienience overload using C-String - PType operator() (const char* file, Category& cat); + PType operator() (const char* file, const Category& cat); PType operator() (const char* file, asset::Kind); }; diff --git a/src/proc/assetmanager.hpp b/src/proc/assetmanager.hpp index 9055c13f8..1dc05f584 100644 --- a/src/proc/assetmanager.hpp +++ b/src/proc/assetmanager.hpp @@ -103,7 +103,8 @@ namespace asset AssetManager (); friend class cinelerra::singleton::Static; - + + private: static void detach_child (PAsset&, IDA); }; diff --git a/tests/components/proc/asset/createassettest.cpp b/tests/components/proc/asset/createassettest.cpp index 771c7a568..3aee6c34b 100644 --- a/tests/components/proc/asset/createassettest.cpp +++ b/tests/components/proc/asset/createassettest.cpp @@ -22,18 +22,17 @@ #include "common/test/run.hpp" -//#include "common/factory.hpp" #include "common/util.hpp" #include "proc/assetmanager.hpp" #include "proc/asset/media.hpp" #include "proc/asset/proc.hpp" -//#include +#include #include +using boost::format; using util::isnil; -//using boost::format; using std::string; using std::cout; @@ -43,7 +42,6 @@ namespace asset namespace test { -// typedef Category::Kind Kind; @@ -56,15 +54,23 @@ namespace asset virtual void run(Arg arg) { createMedia(); - } + factoryVariants(); + } + typedef shared_ptr PM; + + /** @test Creating and automatically registering Asset instances. + * Re-Retrieving the newly created objects from AssetManager. + * Checking AssetManager access functions, esp. getting + * different kinds of Assets by ID, querying with the + * wrong Category and querying unknown IDs. + */ void createMedia() { - typedef shared_ptr PM; Category cat(VIDEO,"bin1"); Asset::Ident key("Name-1", cat, "ichthyo", 5); PM mm1 = asset::Media::create(key,"testfile.mov"); - PM mm2 = asset::Media::create(key); + PM mm2 = asset::Media::create("testfile1.mov", cat); PM mm3 = asset::Media::create("testfile2.mov", VIDEO); // Assets have been registered and can be retrieved by ID @@ -91,12 +97,18 @@ namespace asset aMang.getAsset (ID(mm1->getID())); NOTREACHED; } - catch (cinelerra::error::Invalid) { } + catch (cinelerra::error::Invalid& exe) {ASSERT (exe.getID()==CINELERRA_ERROR_WRONG_ASSET_KIND);} + try + { // try accessing nonexistant ID + aMang.getAsset (ID (1234567890)); + NOTREACHED; + } + catch (cinelerra::error::Invalid& exe) {ASSERT (exe.getID()==CINELERRA_ERROR_UNKNOWN_ASSET_ID);} // checking the Ident-Fields ASSERT (mm1->ident.name == "Name-1"); - ASSERT (mm2->ident.name == "Name-1"); + ASSERT (mm2->ident.name == "testfile1"); ASSERT (mm3->ident.name == "testfile2"); ASSERT (cat == Category (VIDEO,"bin1")); @@ -105,19 +117,72 @@ namespace asset ASSERT (mm3->ident.category == Category (VIDEO )); ASSERT (mm1->ident.org == "ichthyo"); - ASSERT (mm2->ident.org == "ichthyo"); + ASSERT (mm2->ident.org == "cin3"); ASSERT (mm3->ident.org == "cin3"); ASSERT (mm1->ident.version == 5); - ASSERT (mm2->ident.version == 5); + ASSERT (mm2->ident.version == 1); ASSERT (mm3->ident.version == 1); ASSERT (mm1->getFilename() == "testfile.mov"); - ASSERT (isnil (mm2->getFilename())); + ASSERT (mm2->getFilename() == "testfile1.mov"); ASSERT (mm3->getFilename() == "testfile2.mov"); -/* -////////////////////////////////////////////////////////////////////////////////TODO fuck the compiler!!! -*/ + + showPtr (mm1); + showPtr (mm2); + showPtr (mm3); + showPtr (mX1); + } + + + /** @test different variants of calling the MediaFactory, + * with focus on the behaviour of the basic Asset + * creation machinery. Covers filling out Asset's + * datafields, amending missing pieces of information. + */ + void factoryVariants() + { + PM candi; + + Asset::Ident key1("Au-1", Category(AUDIO), "ichthyo", 5); + candi = asset::Media::create(key1); + ASSERT ( checkProperties (candi, key1, "")); + + candi = asset::Media::create(key1, string("testfile.wav")); + ASSERT ( checkProperties (candi, key1, "testfile.wav")); + + Asset::Ident key2("", Category(AUDIO), "ichthyo", 5); + candi = asset::Media::create(key2, string("testfile2.wav")); + ASSERT ( checkProperties (candi, key2, "testfile2.wav")); + ASSERT (key2.name == "testfile2"); // name filled in automatically + + candi = asset::Media::create(string("testfile3.wav"), Category(AUDIO)); + ASSERT ( checkProperties (candi, Asset::Ident("testfile3", Category(AUDIO), "cin3", 1) + , "testfile3.wav")); + + candi = asset::Media::create("some/path/testfile4.wav", Category(AUDIO)); + ASSERT ( checkProperties (candi, Asset::Ident("testfile4", Category(AUDIO), "cin3", 1) + , "some/path/testfile4.wav")); + + candi = asset::Media::create("", Category(AUDIO,"sub/bin")); + ASSERT ( checkProperties (candi, Asset::Ident("nil", Category(AUDIO,"sub/bin"), "cin3", 1) + , "")); + + candi = asset::Media::create("", AUDIO); + ASSERT ( checkProperties (candi, Asset::Ident("nil", Category(AUDIO), "cin3", 1) + , "")); + } + + bool checkProperties (PM object, Asset::Ident identity, string filename) + { + return identity == object->ident + && filename == object->getFilename(); + } + + void showPtr (PM m) + { + static format fmt("Asset(%s) .... ptr=%d use-count=%d"); + cout << fmt % str(m) % &m % m.use_count() << "\n"; } }; diff --git a/tests/components/proc/asset/identityofassetstest.cpp b/tests/components/proc/asset/identityofassetstest.cpp new file mode 100644 index 000000000..d849fdc15 --- /dev/null +++ b/tests/components/proc/asset/identityofassetstest.cpp @@ -0,0 +1,110 @@ +/* + IdentityOfAssets(Test) - Asset object identity and versioning + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "common/test/run.hpp" +#include "common/util.hpp" + +#include "proc/assetmanager.hpp" +#include "proc/asset/media.hpp" +#include "proc/asset/proc.hpp" + +#include +#include + +using boost::format; +using util::isnil; +using std::string; +using std::cout; + + +namespace asset + { + namespace test + { + + + + + /*********************************************************************** + * @test creating several Assets and checking object identity, + * detection of duplicates and version handling. + * @see proc_interface::AssetManager#reg + * @todo to be written; features are missing as of 9/07 + */ + class IdentityOfAssets_test : public Test + { + virtual void run(Arg arg) + { + createDuplicate(); + } + + typedef shared_ptr PM; + + /** @test produce an ID clash. + * documents the current behaviour of the code as of 9/07 + * @todo this test is expected to break when the detection + * of duplicate registrations is implemented. + */ + void createDuplicate() + { + PM mm1 = asset::Media::create ("testfile1.mov", VIDEO); + + Asset::Ident idi (mm1->ident); // duplicate Ident record + PM mm1X = asset::Media::create (idi); // note: we actually don't call any ctor + ASSERT (mm1 == mm1X); // instead, we got mm1 back. + + PM mm2 = asset::Media::create (idi,"testfile2.mov"); + ASSERT (mm1->getID() == mm2->getID()); // different object, same hash + + AssetManager& aMang = AssetManager::instance(); + ASSERT (aMang.getAsset (mm1->getID()) == mm2); // record of mm1 was replaced by mm2 + ASSERT (aMang.getAsset (mm2->getID()) == mm2); + + ASSERT (aMang.known (mm1->getID())); + ASSERT (aMang.known (mm2->getID())); + ASSERT (mm1->ident.name == "testfile1"); + ASSERT (mm2->ident.name == "testfile1"); + ASSERT (mm1->getFilename() == "testfile1.mov"); + ASSERT (mm2->getFilename() == "testfile2.mov"); + + showPtr (mm1); + showPtr (mm1X); + showPtr (mm2); + } + + void showPtr (PM m) + { + static format fmt("Asset(%s) .... ptr=%d use-count=%d"); + cout << fmt % str(m) % &m % m.use_count() << "\n"; + } + }; + + + /** Register this test class... */ + LAUNCHER (IdentityOfAssets_test, "unit asset"); + + + + } // namespace test + +} // namespace asset From 3927f7d5d81a93558d19cda2fb58b31497a7c1e0 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 17 Sep 2007 05:47:22 +0200 Subject: [PATCH 11/12] WIP: ordering of Assets, dump AssetManager, bugfix (partially...) --- src/common/util.hpp | 2 +- src/proc/asset.cpp | 9 ++- src/proc/asset.hpp | 30 ++++++-- src/proc/asset/category.hpp | 14 +++- src/proc/asset/db.hpp | 10 +++ src/proc/assetmanager.cpp | 13 +++- src/proc/assetmanager.hpp | 9 ++- .../proc/asset/assetdiagnostics.hpp | 73 +++++++++++++++++++ .../components/proc/asset/createassettest.cpp | 28 +++---- .../proc/asset/identityofassetstest.cpp | 22 +++--- 10 files changed, 168 insertions(+), 42 deletions(-) create mode 100644 tests/components/proc/asset/assetdiagnostics.hpp diff --git a/src/common/util.hpp b/src/common/util.hpp index 479142069..7b036e1be 100644 --- a/src/common/util.hpp +++ b/src/common/util.hpp @@ -81,7 +81,7 @@ namespace util */ template inline Oper - for_each (Container& c, Oper& doIt) + for_each (Container& c, Oper doIt) { return std::for_each (c.begin(),c.end(), doIt); } diff --git a/src/proc/asset.cpp b/src/proc/asset.cpp index 0e790becb..622311863 100644 --- a/src/proc/asset.cpp +++ b/src/proc/asset.cpp @@ -46,24 +46,25 @@ namespace asset */ Asset::Asset (const Ident& idi) : ident(idi), id(AssetManager::reg (this, idi)) - { } + { TRACE (assetmem, "ctor Asset(id=%d) : %s p=%x", size_t(id), cStr(this->ident), this ); +} Asset::~Asset () { - TRACE (assetmem, "dtor Asset(id=%d) : %s", size_t(id), cStr(this->ident) ); + TRACE (assetmem, "dtor Asset(id=%d) : %s p=%x", size_t(id), cStr(this->ident), this ); } Asset::Ident::operator string () const { - static format id_tuple("(%2%:%3%.%1% v%4%)"); // ignoring threadsafety + format id_tuple("(%2%:%3%.%1% v%4%)"); return str (id_tuple % name % category % org % version); } Asset::operator string () const { - static format id_tuple("Asset(%2%:%3%.%1% v%4%)"); // ignoring threadsafety + format id_tuple("Asset(%2%:%3%.%1% v%4%)"); return str (id_tuple % ident.name % ident.category % ident.org % ident.version); } diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index d36ab85f2..e6fd207c6 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -175,6 +175,7 @@ namespace asset && name == other.name && category == other.category; } + int compare (const Ident& other) const; operator string () const; }; @@ -261,14 +262,31 @@ namespace asset /** shorthand for refcounting Asset pointers */ typedef shared_ptr PAsset; + /** ordering of Assets based on Ident tuple */ + inline bool operator< (const PAsset& a1, const PAsset& a2) { return a1 && a2 && (-1==a1->ident.compare(a2->ident));} + inline bool operator> (const PAsset& a1, const PAsset& a2) { return a2 < a1; } + inline bool operator>= (const PAsset& a1, const PAsset& a2) { return !(a1 < a2); } + inline bool operator<= (const PAsset& a1, const PAsset& a2) { return !(a1 > a2); } + + /** ordering of Asset Ident tuples. + * @note version is irrelevant */ + inline int Asset::Ident::compare (const Asset::Ident& oi) const + { + int res; + if (1 != (res=category.compare (oi.category))) return res; + if (1 != (res=org.compare (oi.org))) return res; + return name.compare (oi.name); + } + + /** convienient for debugging */ inline string str (const PAsset& a) - { - if (a) - return string (*a.get()); - else - return "Asset(NULL)"; - } + { + if (a) + return string (*a.get()); + else + return "Asset(NULL)"; + } diff --git a/src/proc/asset/category.hpp b/src/proc/asset/category.hpp index f27f46845..5a1bf905c 100644 --- a/src/proc/asset/category.hpp +++ b/src/proc/asset/category.hpp @@ -89,12 +89,22 @@ namespace asset boost::hash_combine(hash, cat.kind_); boost::hash_combine(hash, cat.path_); return hash; - } + } + + int compare (const Category& co) const + { + int res = int(kind_) - int(co.kind_); + if (1 != res) + return res; + else + return path_.compare (co.path_); + } }; inline ostream& operator<< (ostream& os, const Category& cago) { return os << string(cago); } - + + } // namespace asset #endif diff --git a/src/proc/asset/db.hpp b/src/proc/asset/db.hpp index 8ac4207a6..76be677f0 100644 --- a/src/proc/asset/db.hpp +++ b/src/proc/asset/db.hpp @@ -99,6 +99,16 @@ namespace asset { return dynamic_pointer_cast (table[hash]); } + + /** intended for diagnostics */ + void + asList (list& output) const + { + IdHashtable::const_iterator i = table.begin(); + IdHashtable::const_iterator e = table.end(); + for ( ; i!=e ; ++i ) + output.push_back (i->second); + } }; diff --git a/src/proc/assetmanager.cpp b/src/proc/assetmanager.cpp index 0fba91b52..89843b1d6 100644 --- a/src/proc/assetmanager.cpp +++ b/src/proc/assetmanager.cpp @@ -27,7 +27,7 @@ #include "common/multithread.hpp" #include "common/util.hpp" -#include +//#include #include #include @@ -191,6 +191,17 @@ namespace asset } + + list + AssetManager::listContent() const + { + list res; + registry.asList (res); + res.sort(); + return res; + } + + } // namespace asset diff --git a/src/proc/assetmanager.hpp b/src/proc/assetmanager.hpp index 1dc05f584..8ccf0ac61 100644 --- a/src/proc/assetmanager.hpp +++ b/src/proc/assetmanager.hpp @@ -43,9 +43,11 @@ #include #include +#include #include using std::string; +using std::list; @@ -86,6 +88,10 @@ namespace asset void remove (IDA id) throw(cinelerra::error::Invalid, cinelerra::error::State); + /** extract a sorted list of all registered Assets */ + list listContent() const; + + protected: /** registers an asset object in the internal DB, providing its unique key. @@ -96,7 +102,8 @@ namespace asset throw(cinelerra::error::Invalid); /** deleter function used by the Asset smart pointers to delet Asset objects */ - static void destroy (Asset* m) { delete m; } + static void destroy (Asset* m) { TRACE (assetmem, "call destroy (Asset(id=%d)) p=%x", m? size_t(m->getID()):0, m ); + delete m; } friend Asset::Asset (const Asset::Ident& idi); diff --git a/tests/components/proc/asset/assetdiagnostics.hpp b/tests/components/proc/asset/assetdiagnostics.hpp new file mode 100644 index 000000000..d5425ee66 --- /dev/null +++ b/tests/components/proc/asset/assetdiagnostics.hpp @@ -0,0 +1,73 @@ +/* + ASSETDIAGNOSTICS.hpp - collection of test and debug helpers + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file assetdiagnostics.hpp + ** Small helper and diagnosic functions related to Asset and AssetManager + ** + ** @see assetmanager.hpp + ** @see CreateAsset_test + ** @see IdentityOfAssets_test + */ + + +#ifndef ASSET_ASSETDIAGNOSTICS_H +#define ASSET_ASSETDIAGNOSTICS_H + + +#include "proc/assetmanager.hpp" +#include "common/util.hpp" + +#include +#include +#include + +using util::for_each; +using boost::format; +using boost::bind; +using std::string; +using std::cout; + + +namespace asset + { + + inline void dump (const PAsset& aa) + { + if (!aa) + cout << "Asset(NULL)\n"; + else + { + format fmt("%s %|50T.| id=%d sP=%x ptr=%x use-count=%d"); + cout << fmt % str(aa) % aa->getID() % &aa % aa.get() % aa.use_count() << "\n"; + } } + + inline void dumpAssetManager () + { + list assets (AssetManager::instance().listContent()); + cout << "----all-registered-Assets----\n"; + for_each (assets, bind (&dump, _1)); + } + + + +} // namespace asset +#endif diff --git a/tests/components/proc/asset/createassettest.cpp b/tests/components/proc/asset/createassettest.cpp index 3aee6c34b..b5f449787 100644 --- a/tests/components/proc/asset/createassettest.cpp +++ b/tests/components/proc/asset/createassettest.cpp @@ -28,13 +28,10 @@ #include "proc/asset/media.hpp" #include "proc/asset/proc.hpp" -#include -#include +#include "proc/asset/assetdiagnostics.hpp" -using boost::format; using util::isnil; using std::string; -using std::cout; namespace asset @@ -55,6 +52,7 @@ namespace asset { createMedia(); factoryVariants(); + dumpAssetManager(); } typedef shared_ptr PM; @@ -81,6 +79,9 @@ namespace asset ASSERT (aMang.getAsset (mm1->getID()) != mm2); + cout << "== 1 ==\n"; + dumpAssetManager(); + PAsset aa1 = aMang.getAsset (ID(mm1->getID())); // note we get an Asset ref ASSERT (aa1 == mm1); PM mX1 = aMang.getAsset (mm1->getID()); // ..and now we get a Media ref @@ -91,6 +92,9 @@ namespace asset ASSERT (aMang.known (mm2->getID())); ASSERT (aMang.known (mm3->getID())); + cout << "== 2 ==\n"; + dumpAssetManager(); + ASSERT ( !aMang.known (mm3->getID(), Category(AUDIO))); // not found within AUDIO-Category try { // can't be found if specifying wrong Asset kind.... @@ -128,10 +132,12 @@ namespace asset ASSERT (mm2->getFilename() == "testfile1.mov"); ASSERT (mm3->getFilename() == "testfile2.mov"); - showPtr (mm1); - showPtr (mm2); - showPtr (mm3); - showPtr (mX1); + dump (mm1); + dump (mm2); + dump (mm3); + dump (mX1); + cout << "== 3 ==\n"; + dumpAssetManager(); } @@ -178,12 +184,6 @@ namespace asset return identity == object->ident && filename == object->getFilename(); } - - void showPtr (PM m) - { - static format fmt("Asset(%s) .... ptr=%d use-count=%d"); - cout << fmt % str(m) % &m % m.use_count() << "\n"; - } }; diff --git a/tests/components/proc/asset/identityofassetstest.cpp b/tests/components/proc/asset/identityofassetstest.cpp index d849fdc15..d55623538 100644 --- a/tests/components/proc/asset/identityofassetstest.cpp +++ b/tests/components/proc/asset/identityofassetstest.cpp @@ -28,13 +28,10 @@ #include "proc/asset/media.hpp" #include "proc/asset/proc.hpp" -#include -#include +#include "proc/asset/assetdiagnostics.hpp" -using boost::format; using util::isnil; using std::string; -using std::cout; namespace asset @@ -56,6 +53,7 @@ namespace asset virtual void run(Arg arg) { createDuplicate(); + cout << "ausis\n"; } typedef shared_ptr PM; @@ -72,8 +70,9 @@ namespace asset Asset::Ident idi (mm1->ident); // duplicate Ident record PM mm1X = asset::Media::create (idi); // note: we actually don't call any ctor ASSERT (mm1 == mm1X); // instead, we got mm1 back. - + cout << "usi-v " << mm1.use_count() <<"\n"; PM mm2 = asset::Media::create (idi,"testfile2.mov"); + cout << "usi-n " << mm1.use_count() <<"\n"; ASSERT (mm1->getID() == mm2->getID()); // different object, same hash AssetManager& aMang = AssetManager::instance(); @@ -87,16 +86,13 @@ namespace asset ASSERT (mm1->getFilename() == "testfile1.mov"); ASSERT (mm2->getFilename() == "testfile2.mov"); - showPtr (mm1); - showPtr (mm1X); - showPtr (mm2); + cout << "use-cnt at end " << mm1.use_count() <<"\n"; + dump (mm1); + dump (mm1X); + dump (mm2); + dumpAssetManager(); } - void showPtr (PM m) - { - static format fmt("Asset(%s) .... ptr=%d use-count=%d"); - cout << fmt % str(m) % &m % m.use_count() << "\n"; - } }; From 14d1c5a34b499ec152ae3e6535a63492623a04f5 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 18 Sep 2007 05:16:56 +0200 Subject: [PATCH 12/12] basic AssetManager works now (creating, registering, querying), including memory management. Ordering is still WIP. --- src/proc/asset.cpp | 6 +- src/proc/asset.hpp | 17 ++- src/proc/asset/db.hpp | 20 ++- src/proc/assetmanager.hpp | 3 +- tests/51asset.tests | 12 +- .../proc/asset/assetdiagnostics.hpp | 4 +- .../components/proc/asset/createassettest.cpp | 25 ++-- .../proc/asset/identityofassetstest.cpp | 18 +-- .../proc/asset/orderingofassetstest.cpp | 125 ++++++++++++++++++ 9 files changed, 194 insertions(+), 36 deletions(-) create mode 100644 tests/components/proc/asset/orderingofassetstest.cpp diff --git a/src/proc/asset.cpp b/src/proc/asset.cpp index 622311863..460464a8e 100644 --- a/src/proc/asset.cpp +++ b/src/proc/asset.cpp @@ -27,6 +27,8 @@ #include +#include +#include using boost::format; using util::cStr; @@ -46,12 +48,12 @@ namespace asset */ Asset::Asset (const Ident& idi) : ident(idi), id(AssetManager::reg (this, idi)) - { TRACE (assetmem, "ctor Asset(id=%d) : %s p=%x", size_t(id), cStr(this->ident), this ); + { TRACE (assetmem, "ctor Asset(id=%lu) : adr=%x %s", size_t(id), this, cStr(this->ident) ); } Asset::~Asset () { - TRACE (assetmem, "dtor Asset(id=%d) : %s p=%x", size_t(id), cStr(this->ident), this ); + TRACE (assetmem, "dtor Asset(id=%lu) : adr=%x", size_t(id), this ); } diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index e6fd207c6..a6e3b1ad8 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -175,20 +175,30 @@ namespace asset && name == other.name && category == other.category; } + bool operator!= (const Ident& other) const + { + return !operator==(other); + } + int compare (const Ident& other) const; operator string () const; }; + + + /* ===== Asset ID and Datafields ===== */ + public: const Ident ident; ///< Asset identification tuple + virtual const ID& getID() const { return id; } + virtual operator string () const; + protected: const ID id; ///< Asset primary key. - - protected: /** additional classification, selections or departments this asset belongs to. * Groups are optional, non-exclusive and may be overlapping. */ @@ -209,7 +219,7 @@ namespace asset * Calling this base ctor causes registration with AssetManager. */ Asset (const Ident& idi); - virtual ~Asset() = 0; + virtual ~Asset() = 0; ///< @note Asset is abstract /** release all links to other Asset objects held internally. * The lifecycle of Asset objects is managed by smart pointers @@ -230,6 +240,7 @@ namespace asset friend class AssetManager; + public: /** List of entities this asset depends on or requires to be functional. * May be empty. The head of this list can be considered the primary prerequisite diff --git a/src/proc/asset/db.hpp b/src/proc/asset/db.hpp index 76be677f0..b9faa0a42 100644 --- a/src/proc/asset/db.hpp +++ b/src/proc/asset/db.hpp @@ -88,6 +88,7 @@ namespace asset friend class cinelerra::singleton::Static; + public: template void put (ID hash, shared_ptr& ptr) { table[hash] = static_pointer_cast (ptr); } @@ -95,20 +96,33 @@ namespace asset template shared_ptr - get (ID hash) + get (ID hash) const { - return dynamic_pointer_cast (table[hash]); + return dynamic_pointer_cast (find (hash)); } + /** intended for diagnostics */ void - asList (list& output) const + asList (list& output) const { IdHashtable::const_iterator i = table.begin(); IdHashtable::const_iterator e = table.end(); for ( ; i!=e ; ++i ) output.push_back (i->second); } + + private: + const PAsset & + find (size_t hash) const + { + static const PAsset NULLP; + IdHashtable::const_iterator i = table.find (hash); + if (i == table.end()) + return NULLP; // empty ptr signaling "not found" + else + return i->second; + } }; diff --git a/src/proc/assetmanager.hpp b/src/proc/assetmanager.hpp index 8ccf0ac61..c677f6ef4 100644 --- a/src/proc/assetmanager.hpp +++ b/src/proc/assetmanager.hpp @@ -102,8 +102,7 @@ namespace asset throw(cinelerra::error::Invalid); /** deleter function used by the Asset smart pointers to delet Asset objects */ - static void destroy (Asset* m) { TRACE (assetmem, "call destroy (Asset(id=%d)) p=%x", m? size_t(m->getID()):0, m ); - delete m; } + static void destroy (Asset* m) { delete m; } friend Asset::Asset (const Asset::Ident& idi); diff --git a/tests/51asset.tests b/tests/51asset.tests index 37b7dac4f..4c87542f4 100644 --- a/tests/51asset.tests +++ b/tests/51asset.tests @@ -2,7 +2,8 @@ TESTING "Component Test Suite: Asset Manager" ./test-components --group=asset -PLANNED "CreateAsset_test" CreateAsset_test <getID() % &aa % aa.get() % aa.use_count() << "\n"; + format fmt("%s %|50T.| id=%s adr=%x smart-ptr=%x use-count=%d"); + cout << fmt % str(aa) % aa->getID() % aa.get() % &aa % (aa.use_count() - 1) << "\n"; } } inline void dumpAssetManager () diff --git a/tests/components/proc/asset/createassettest.cpp b/tests/components/proc/asset/createassettest.cpp index b5f449787..00fa049f0 100644 --- a/tests/components/proc/asset/createassettest.cpp +++ b/tests/components/proc/asset/createassettest.cpp @@ -52,9 +52,14 @@ namespace asset { createMedia(); factoryVariants(); - dumpAssetManager(); + + if (!isnil (arg)) + dumpAssetManager(); + TRACE (assetmem, "leaving CreateAsset_test::run()"); } + + typedef shared_ptr PM; /** @test Creating and automatically registering Asset instances. @@ -79,9 +84,6 @@ namespace asset ASSERT (aMang.getAsset (mm1->getID()) != mm2); - cout << "== 1 ==\n"; - dumpAssetManager(); - PAsset aa1 = aMang.getAsset (ID(mm1->getID())); // note we get an Asset ref ASSERT (aa1 == mm1); PM mX1 = aMang.getAsset (mm1->getID()); // ..and now we get a Media ref @@ -92,22 +94,19 @@ namespace asset ASSERT (aMang.known (mm2->getID())); ASSERT (aMang.known (mm3->getID())); - cout << "== 2 ==\n"; - dumpAssetManager(); - ASSERT ( !aMang.known (mm3->getID(), Category(AUDIO))); // not found within AUDIO-Category try { // can't be found if specifying wrong Asset kind.... aMang.getAsset (ID(mm1->getID())); NOTREACHED; } - catch (cinelerra::error::Invalid& exe) {ASSERT (exe.getID()==CINELERRA_ERROR_WRONG_ASSET_KIND);} + catch (cinelerra::error::Invalid& xxx) {ASSERT (xxx.getID()==CINELERRA_ERROR_WRONG_ASSET_KIND);} try { // try accessing nonexistant ID aMang.getAsset (ID (1234567890)); NOTREACHED; } - catch (cinelerra::error::Invalid& exe) {ASSERT (exe.getID()==CINELERRA_ERROR_UNKNOWN_ASSET_ID);} + catch (cinelerra::error::Invalid& xxx) {ASSERT (xxx.getID()==CINELERRA_ERROR_UNKNOWN_ASSET_ID);} // checking the Ident-Fields @@ -132,12 +131,8 @@ namespace asset ASSERT (mm2->getFilename() == "testfile1.mov"); ASSERT (mm3->getFilename() == "testfile2.mov"); - dump (mm1); - dump (mm2); - dump (mm3); - dump (mX1); - cout << "== 3 ==\n"; - dumpAssetManager(); + + TRACE (assetmem, "leaving test method scope"); } diff --git a/tests/components/proc/asset/identityofassetstest.cpp b/tests/components/proc/asset/identityofassetstest.cpp index d55623538..2e62963bc 100644 --- a/tests/components/proc/asset/identityofassetstest.cpp +++ b/tests/components/proc/asset/identityofassetstest.cpp @@ -53,9 +53,14 @@ namespace asset virtual void run(Arg arg) { createDuplicate(); - cout << "ausis\n"; + + if (!isnil (arg)) + dumpAssetManager(); + TRACE (assetmem, "leaving IdentityOfAssets_test::run()"); } + + typedef shared_ptr PM; /** @test produce an ID clash. @@ -70,9 +75,9 @@ namespace asset Asset::Ident idi (mm1->ident); // duplicate Ident record PM mm1X = asset::Media::create (idi); // note: we actually don't call any ctor ASSERT (mm1 == mm1X); // instead, we got mm1 back. - cout << "usi-v " << mm1.use_count() <<"\n"; + PM mm2 = asset::Media::create (idi,"testfile2.mov"); - cout << "usi-n " << mm1.use_count() <<"\n"; + ASSERT (mm1->getID() == mm2->getID()); // different object, same hash AssetManager& aMang = AssetManager::instance(); @@ -86,11 +91,8 @@ namespace asset ASSERT (mm1->getFilename() == "testfile1.mov"); ASSERT (mm2->getFilename() == "testfile2.mov"); - cout << "use-cnt at end " << mm1.use_count() <<"\n"; - dump (mm1); - dump (mm1X); - dump (mm2); - dumpAssetManager(); + + TRACE (assetmem, "leaving test method scope"); } }; diff --git a/tests/components/proc/asset/orderingofassetstest.cpp b/tests/components/proc/asset/orderingofassetstest.cpp new file mode 100644 index 000000000..4e6137224 --- /dev/null +++ b/tests/components/proc/asset/orderingofassetstest.cpp @@ -0,0 +1,125 @@ +/* + OrderingOfAssets(Test) - equality and comparisons + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "common/test/run.hpp" +#include "common/util.hpp" + +#include "proc/assetmanager.hpp" +#include "proc/asset/media.hpp" +#include "proc/asset/proc.hpp" + +#include "proc/asset/assetdiagnostics.hpp" + +using util::isnil; +using std::string; + + +namespace asset + { + namespace test + { + + + + + /****************************************************** + * @test validate the equality and order relations of + * Asset::Ident and Asset objects. + * @see Asset::Ident#compare + */ + class OrderingOfAssets_test : public Test + { + virtual void run(Arg arg) + { + typedef shared_ptr PM; + + Asset::Ident key1("Au-1", Category(AUDIO), "ichthyo", 5); + PM mm1 = asset::Media::create(key1, "Name-1"); + + Asset::Ident key2("Au-1", Category(AUDIO), "ichthyo", 7); + PM mm2 = asset::Media::create(key2, "Name-2"); + + Asset::Ident key3("Au-2", Category(AUDIO), "ichthyo", 5); + PM mm3 = asset::Media::create(key3, "Name-3"); + + Asset::Ident key4("Au-2", Category(AUDIO), "stega", 5); + PM mm4 = asset::Media::create(key4, "Name-4"); + + Asset::Ident key5("Au-1", Category(VIDEO), "ichthyo", 5); + PM mm5 = asset::Media::create(key5, "Name-5"); + + + // ordering of keys + ASSERT (key1 == key2); + ASSERT (key2 != key3); + ASSERT (key3 != key4); + ASSERT (key4 != key5); + ASSERT (key1 != key5); + + ASSERT (-1 == key2.compare(key3)); + ASSERT (+1 == key3.compare(key2)); + + ASSERT (-1 == key3.compare(key4)); + ASSERT (-1 == key4.compare(key5)); + ASSERT (-1 == key1.compare(key5)); + ASSERT (-1 == key2.compare(key5)); + ASSERT (-1 == key3.compare(key5)); + ASSERT (-1 == key1.compare(key3)); + ASSERT (-1 == key1.compare(key4)); + ASSERT (-1 == key2.compare(key4)); + + + // ordering of Asset smart ptrs + ASSERT (mm1 == mm2); + ASSERT (mm2 != mm3); + ASSERT (mm3 != mm4); + ASSERT (mm4 != mm5); + ASSERT (mm1 != mm5); + + ASSERT (mm2 < mm3); + ASSERT (mm2 <= mm3); + ASSERT (mm3 > mm2); + ASSERT (mm3 >= mm2); + + ASSERT (mm3 < mm4); + ASSERT (mm4 < mm5); + ASSERT (mm1 < mm5); + ASSERT (mm2 < mm5); + ASSERT (mm3 < mm5); + ASSERT (mm1 < mm3); + ASSERT (mm1 < mm4); + ASSERT (mm2 < mm4); + + } + + }; + + + /** Register this test class... */ + LAUNCHER (OrderingOfAssets_test, "unit asset"); + + + + } // namespace test + +} // namespace asset