Now able to remove most complicated comparison operators and most usages of boost::operators... In most cases it is sufficient just to define one ''spaceship operator'', and often even that one can be synthesised. However — we still use boost::operators for arithmetic types, notably the `lib::time::TimeValue`, which is addable and mutipliable
337 lines
11 KiB
C++
337 lines
11 KiB
C++
/*
|
||
ASSET.hpp - Superinterface: bookkeeping view of "things" present in the session
|
||
|
||
Copyright (C)
|
||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||
|
||
**Lumiera** 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. See the file COPYING for further details.
|
||
|
||
*/
|
||
|
||
/** @file asset.hpp
|
||
** @ingroup asset
|
||
** Steam-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.
|
||
**
|
||
** 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 utilising 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<Media>. 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 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
|
||
*/
|
||
|
||
|
||
#ifndef STEAM_INTERFACE_ASSET_H
|
||
#define STEAM_INTERFACE_ASSET_H
|
||
|
||
|
||
#include "lib/error.hpp"
|
||
#include "lib/nocopy.hpp"
|
||
#include "include/logging.h"
|
||
#include "steam/asset/category.hpp"
|
||
#include "lib/hash-value.h"
|
||
#include "lib/p.hpp"
|
||
|
||
#include <type_traits>
|
||
#include <compare>
|
||
#include <string>
|
||
#include <vector>
|
||
#include <set>
|
||
|
||
|
||
using std::string;
|
||
using std::vector;
|
||
using std::set;
|
||
|
||
|
||
namespace steam {
|
||
namespace asset {
|
||
|
||
namespace error = lumiera::error;
|
||
|
||
using std::size_t;
|
||
using std::shared_ptr;
|
||
using std::static_pointer_cast;
|
||
|
||
using lib::HashVal;
|
||
|
||
|
||
|
||
/**
|
||
* thin wrapper around a size_t hash ID
|
||
* used as primary key for all Asset objects.
|
||
* The Template parameter is intended for tagging
|
||
* the ID with type information, causing the
|
||
* compiler to select specialised behaviour
|
||
* for the different kinds of Assets.
|
||
* @see Asset
|
||
* @see AssetManager#getID generating ID values
|
||
* @see asset::Media
|
||
* @see ID<asset::Media>
|
||
*
|
||
* @todo it would be desirable to use EntryID instead ///////////////////////////////////////////TICKET #739 : make identification schemes compatible
|
||
*/
|
||
template<class KIND>
|
||
class ID
|
||
{
|
||
HashVal hash_;
|
||
public:
|
||
ID (HashVal id) : hash_(id) {}
|
||
ID (const KIND& asset) : hash_(asset.getID()) {}
|
||
operator HashVal() const { return hash_; }
|
||
|
||
static ID INVALID;
|
||
};
|
||
|
||
class DB;
|
||
class Asset;
|
||
class AssetManager;
|
||
typedef const ID<Asset>& IDA;
|
||
typedef lib::P<Asset> PAsset;
|
||
typedef lib::P<const Asset> PcAsset;
|
||
|
||
|
||
|
||
|
||
|
||
/**
|
||
* Superinterface describing especially bookkeeping properties.
|
||
* As of 09/2007, there are four <b>Kinds</b> 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 session (e.g. Tracks)
|
||
* - asset::Meta representing metadata, parametrisation, customisation.
|
||
*
|
||
* And of course there are various concrete Asset subclasses, like asset::Clip,
|
||
* asset::Effect, asset::Codec, 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. It is possible to copy the PAsset (smart pointer) though.
|
||
*
|
||
* @since 09/2007
|
||
* @author Ichthyo
|
||
*/
|
||
class Asset
|
||
: util::NonCopyable
|
||
{
|
||
public:
|
||
|
||
/**
|
||
* a POD comprised of all the information
|
||
* sufficiently identifying any given Asset.
|
||
*/
|
||
struct Ident
|
||
{
|
||
/** element ID, comprehensible but sanitised.
|
||
* 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 component name to be more generic (e.g. "blur").
|
||
* Default for all assets provided by the core Lumiera codebase is "lumi".
|
||
*/
|
||
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 (string const& n
|
||
,Category const& cat
|
||
,string const& o = "lumi"
|
||
,const uint ver=1);
|
||
|
||
|
||
/** ordering of Assets is based on the ordering of Ident tuples,
|
||
* descending from Category to origin and finally to the asset element ID.
|
||
* @note version info is ignored for this comparison */
|
||
auto operator<=>(Ident const& oi) const { return std::tie ( category, org, name)
|
||
<=> std::tie (oi.category,oi.org,oi.name); }
|
||
bool operator== (Ident const& oi) const { return 0 == *this <=> oi; }
|
||
|
||
|
||
operator string () const;
|
||
|
||
bool isValid() const;
|
||
};
|
||
|
||
|
||
/* ===== Asset ID and Datafields ===== */
|
||
|
||
public:
|
||
const Ident ident; ///< Asset identification tuple
|
||
|
||
virtual const ID<Asset>& getID() const { return id; }
|
||
|
||
|
||
bool operator== (Asset const& oa) const { return ident == oa.ident; }
|
||
auto operator<=>(Asset const& oa) const { return ident <=> oa.ident; }
|
||
|
||
virtual operator string () const;
|
||
|
||
|
||
|
||
protected:
|
||
const ID<Asset> id; ///< Asset primary key.
|
||
|
||
/** additional classification, selections or departments this asset belongs to.
|
||
* Groups are optional, non-exclusive and may be overlapping.
|
||
*/
|
||
set<string> groups;
|
||
|
||
/** user visible Name-ID. To be localised. */
|
||
const string shortDesc;
|
||
|
||
/** user visible qualification of the thing, unit or concept represented by this asset.
|
||
* preferably "in one line". To be localised. */
|
||
const string longDesc;
|
||
|
||
vector<PAsset> parents;
|
||
vector<PAsset> dependants;
|
||
|
||
bool enabled;
|
||
|
||
|
||
|
||
protected:
|
||
/** Asset is a Interface class; usually, objects of
|
||
* concrete subclasses are created via specialised Factories.
|
||
* Calling this base ctor causes registration with AssetManager.
|
||
*/
|
||
Asset (const Ident& idi);
|
||
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
|
||
* and the Asset manager. Calling \c unlink() breaks interconnections
|
||
* to other Assets in the central Object network comprising the session.
|
||
* Especially, the \em downward links to dependent entities are released,
|
||
* while the primary (upward) smart-ptr links to our prerequisites are
|
||
* still retained. The rationale is, after releasing these redundant
|
||
* or cyclic interlinking, when the AssetManager removes its DB entry
|
||
* for this asset, the smart pointer goes out of scope and causes
|
||
* unwinding of the whole dependency chain.
|
||
*/
|
||
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);
|
||
|
||
/** establish a connection between this and the given parent asset,
|
||
* denoting we are in some way dependent on the parent. */
|
||
void defineDependency (PAsset parent);
|
||
void defineDependency (Asset& parent);
|
||
|
||
friend class AssetManager;
|
||
friend class DB;
|
||
|
||
private:
|
||
void unregister (PAsset& other);
|
||
|
||
|
||
|
||
|
||
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
|
||
*/
|
||
const vector<PAsset>& getParents () const { return parents; }
|
||
|
||
/** 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.
|
||
*/
|
||
const vector<PAsset>& getDependant () const { return dependants; }
|
||
|
||
/** weather this asset is switched on and consequently
|
||
* included in the fixture and participates in rendering
|
||
*/
|
||
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
|
||
* @return \c false if the state could not be changed
|
||
* due to parent objects being disabled
|
||
*/
|
||
bool enable (bool on=true);
|
||
|
||
|
||
};
|
||
|
||
|
||
|
||
|
||
/** promote subtype-ptr to PAsset, e.g. for comparing */
|
||
template<class A>
|
||
inline const PcAsset
|
||
pAsset (shared_ptr<A> const& subPtr)
|
||
{
|
||
return static_pointer_cast<const Asset,A> (subPtr);
|
||
}
|
||
|
||
|
||
/** type trait for detecting a shared-ptr-to-asset */
|
||
template <class X>
|
||
struct is_pAsset : std::false_type { };
|
||
|
||
template <class A>
|
||
struct is_pAsset<shared_ptr<A>>
|
||
: std::is_base_of<Asset, A> { };
|
||
|
||
|
||
/** marker constant denoting a NIL asset */
|
||
template<class KIND>
|
||
ID<KIND> ID<KIND>::INVALID = ID{0};
|
||
|
||
|
||
}} // namespace steam::asset
|
||
|
||
|
||
|
||
namespace proc_interface {
|
||
|
||
using steam::asset::Asset;
|
||
using steam::asset::Category;
|
||
using steam::asset::ID;
|
||
using steam::asset::IDA;
|
||
using steam::asset::PAsset;
|
||
}
|
||
|
||
#endif
|