Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 40 additions & 23 deletions src/opentimelineio/anyDictionary.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,39 @@

namespace opentimelineio { namespace OPENTIMELINEIO_VERSION {

/**
* An AnyDictionary has exactly the same API as
* std::map<std::string, std::any>
*
* except that it records a "time-stamp" that bumps monotonically every time an
* operation that would invalidate iterators is performed.
* (This happens for operator=, clear, erase, insert, swap). The stamp also
* lets external observers know when the map has been destroyed (which includes
* the case of the map being relocated in memory).
*
* This allows us to hand out iterators that can be aware of mutation and moves
* and take steps to safe-guard themselves from causing a crash. (Yes,
* I'm talking to you, Python...)
*/
/// @brief This class provides a replacement for "std::map<std::string, std::any>".
///
/// This class has exactly the same API as "std::map<std::string, std::any>",
/// except that it records a "time-stamp" that bumps monotonically every time an
/// operation that would invalidate iterators is performed (this happens for
/// operator =, clear, erase, insert, and swap). The stamp also lets external
/// observers know when the map has been destroyed (which includes the case of
/// the map being relocated in memory).
///
/// This allows us to hand out iterators that can be aware of mutation and moves
/// and take steps to safe-guard themselves from causing a crash. (Yes, I'm
/// talking to you, Python...)
class AnyDictionary : private std::map<std::string, std::any>
{
public:
using map::map;

/// @brief Create an empty dictionary.
AnyDictionary()
: map{}
, _mutation_stamp{}
{}

// to be safe, avoid brace-initialization so as to not trigger
// list initialization behavior in older compilers:
/// @brief Create a copy of a dictionary.
///
/// To be safe, avoid brace-initialization so as to not trigger
/// list initialization behavior in older compilers:
AnyDictionary(const AnyDictionary& other)
: map(other)
, _mutation_stamp{}
{}

/// @brief Destructor.
~AnyDictionary()
{
if (_mutation_stamp)
Expand All @@ -52,13 +54,15 @@ class AnyDictionary : private std::map<std::string, std::any>
}
}

/// @brief Copy operator.
AnyDictionary& operator=(const AnyDictionary& other)
{
mutate();
map::operator=(other);
return *this;
}

/// @brief Move operator.
AnyDictionary& operator=(AnyDictionary&& other)
{
mutate();
Expand All @@ -67,6 +71,7 @@ class AnyDictionary : private std::map<std::string, std::any>
return *this;
}

/// @brief Copy operator.
AnyDictionary& operator=(std::initializer_list<value_type> ilist)
{
mutate();
Expand All @@ -88,6 +93,7 @@ class AnyDictionary : private std::map<std::string, std::any>
using map::rbegin;
using map::rend;

/// @brief Clear the dictionary.
void clear() noexcept
{
mutate();
Expand All @@ -97,36 +103,40 @@ class AnyDictionary : private std::map<std::string, std::any>
using map::emplace_hint;
using map::insert;

/// @brief Erase an item.
iterator erase(const_iterator pos)
{
mutate();
return map::erase(pos);
}

/// @brief Erase a range of items.
iterator erase(const_iterator first, const_iterator last)
{
mutate();
return map::erase(first, last);
}

/// @brief Erase an item with the given key.
size_type erase(const key_type& key)
{
mutate();
return map::erase(key);
}

/// @brief Swap dictionaries.
void swap(AnyDictionary& other)
{
mutate();
other.mutate();
map::swap(other);
}

/// @TODO: remove all of these @{

// if key is in this, and the type of key matches the type of result, then
// set result to the value of std::any_cast<type>(this[key]) and return true,
// otherwise return false
/// @brief Return whether the given key has been set.
///
/// If key is in this, and the type of key matches the type of result, then
/// set result to the value of std::any_cast<type>(this[key]) and return true,
/// otherwise return false.
template <typename containedType>
bool get_if_set(const std::string& key, containedType* result) const
{
Expand All @@ -150,13 +160,16 @@ class AnyDictionary : private std::map<std::string, std::any>
}
}

/// @brief Return whether the dictionary contains the given key.
inline bool has_key(const std::string& key) const
{
return (this->find(key) != this->end());
}

// if key is in this, place the value in result and return true, otherwise
// store the value in result at key and return false
/// @brief Set the default for the given key.
///
/// If key is in this, place the value in result and return true, otherwise
/// store the value in result at key and return false.
template <typename containedType>
bool set_default(const std::string& key, containedType* result)
{
Expand Down Expand Up @@ -210,8 +223,10 @@ class AnyDictionary : private std::map<std::string, std::any>
using map::size_type;
using map::value_type;

/// @brief This struct provides a mutation time stamp.
struct MutationStamp
{
/// @brief Create a new time stamp.
constexpr MutationStamp(AnyDictionary* d) noexcept
: stamp{ 1 }
, any_dictionary{ d }
Expand All @@ -223,6 +238,7 @@ class AnyDictionary : private std::map<std::string, std::any>
MutationStamp(MutationStamp const&) = delete;
MutationStamp& operator=(MutationStamp const&) = delete;

/// @brief Destructor.
~MutationStamp()
{
if (any_dictionary)
Expand All @@ -249,6 +265,7 @@ class AnyDictionary : private std::map<std::string, std::any>
}
};

/// @brief Get or crate a mutation time stamp.
MutationStamp* get_or_create_mutation_stamp()
{
if (!_mutation_stamp)
Expand Down
37 changes: 23 additions & 14 deletions src/opentimelineio/anyVector.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,35 @@

namespace opentimelineio { namespace OPENTIMELINEIO_VERSION {

/**
* An AnyVector has exactly the same API as
* std::vector<std::any>
*
* except that it records a "time-stamp" that
* lets external observers know when the vector has been destroyed (which includes
* the case of the vector being relocated in memory).
*
* This allows us to hand out iterators that can be aware of moves
* and take steps to safe-guard themselves from causing a crash.
*/

/// @brief This class provides a replacement for "std::vector<std::any>".
///
/// This class has exactly the same API as "std::vector<std::any>", except
/// that it records a "time-stamp" that lets external observers know when
/// the vector has been destroyed (which includes the case of the vector
/// being relocated in memory).
///
/// This allows us to hand out iterators that can be aware of moves
/// and take steps to safe-guard themselves from causing a crash.
class AnyVector : private std::vector<std::any>
{
public:
using vector::vector;

/// @brief Create an empty vector.
AnyVector()
: _mutation_stamp{}
{}

// must avoid brace-initialization so as to not trigger
// list initialization behavior in older compilers:
/// @brief Create a copy of a vector.
///
/// To be safe, avoid brace-initialization so as to not trigger
/// list initialization behavior in older compilers:
AnyVector(const AnyVector& other)
: vector(other)
, _mutation_stamp{ nullptr }
{}

/// @brief Destructor.
~AnyVector()
{
if (_mutation_stamp)
Expand All @@ -47,18 +48,21 @@ class AnyVector : private std::vector<std::any>
}
}

/// @brief Copy operator.
AnyVector& operator=(const AnyVector& other)
{
vector::operator=(other);
return *this;
}

/// @brief Move operator.
AnyVector& operator=(AnyVector&& other)
{
vector::operator=(other);
return *this;
}

/// @brief Copy operator.
AnyVector& operator=(std::initializer_list<value_type> ilist)
{
vector::operator=(ilist);
Expand Down Expand Up @@ -113,10 +117,13 @@ class AnyVector : private std::vector<std::any>
using vector::size_type;
using vector::value_type;

/// @brief Swap vectors.
void swap(AnyVector& other) { vector::swap(other); }

/// @brief This struct provides a mutation time stamp.
struct MutationStamp
{
/// @brief Create a new time stamp.
MutationStamp(AnyVector* v)
: any_vector{ v }
, owning{ false }
Expand All @@ -127,6 +134,7 @@ class AnyVector : private std::vector<std::any>
MutationStamp(MutationStamp const&) = delete;
MutationStamp& operator=(MutationStamp const&) = delete;

/// @brief Destructor.
~MutationStamp()
{
if (any_vector)
Expand All @@ -151,6 +159,7 @@ class AnyVector : private std::vector<std::any>
}
};

/// @brief Get or create a mutation time stamp.
MutationStamp* get_or_create_mutation_stamp()
{
if (!_mutation_stamp)
Expand Down
49 changes: 41 additions & 8 deletions src/opentimelineio/clip.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@

namespace opentimelineio { namespace OPENTIMELINEIO_VERSION {

/// @brief A clip is a segment of editable media (usually audio or video).
///
/// Contains a MediaReference and a trim on that media reference.
class Clip : public Item
{
public:
/// @brief The default media within a clip.
static char constexpr default_media_key[] = "DEFAULT_MEDIA";

/// @brief This struct provides the Clip schema.
struct Schema
{
static auto constexpr name = "Clip";
Expand All @@ -22,6 +27,18 @@ class Clip : public Item

using Parent = Item;

/// @brief Create a new clip.
///
/// @param name The name of the clip.
/// @param media_reference The media reference for the clip. Note
/// that the Clip keeps a Retainer to the media reference.
/// @param source_range The source range of the clip.
/// @param metadata The metadata for the clip.
/// @param effects The list of effects for the clip. Note that the
/// the clip keeps a retainer to each effect.
/// @param markers The list of markers for the clip. Note that the
/// the clip keeps a retainer to each marker.
/// @param active_media_reference_key The active media reference.
Clip(
std::string const& name = std::string(),
MediaReference* media_reference = nullptr,
Expand All @@ -31,21 +48,37 @@ class Clip : public Item
std::vector<Marker*> const& markers = std::vector<Marker*>(),
std::string const& active_media_reference_key = default_media_key);

void set_media_reference(MediaReference* media_reference);
/// @name Media References
///@{

/// @brief Set the media reference. Note that the Clip keeps a Retainer to
/// the media reference.
void set_media_reference(MediaReference* media_reference);

/// @brief Return the media reference.
MediaReference* media_reference() const noexcept;

using MediaReferences = std::map<std::string, MediaReference*>;

/// @brief Return the list of media references.
MediaReferences media_references() const noexcept;
void set_media_references(
MediaReferences const& media_references,
std::string const& new_active_key,
ErrorStatus* error_status = nullptr) noexcept;

/// @brief Set the list of media references. Note that the Clip keeps a
/// Retainer to each media reference.
void set_media_references(
MediaReferences const& media_references,
std::string const& new_active_key,
ErrorStatus* error_status = nullptr) noexcept;

/// @brief Return the active media reference.
std::string active_media_reference_key() const noexcept;
void set_active_media_reference_key(
std::string const& new_active_key,
ErrorStatus* error_status = nullptr) noexcept;

/// @brief Set the active media reference.
void set_active_media_reference_key(
std::string const& new_active_key,
ErrorStatus* error_status = nullptr) noexcept;

///@}

TimeRange
available_range(ErrorStatus* error_status = nullptr) const override;
Expand Down
Loading
Loading