summaryrefslogtreecommitdiffstats
path: root/src/track/trackref.h
blob: ef238dad0e69fa09a19cd66e9e519b4f2001d187 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#pragma once

#include "track/trackid.h"
#include "track/trackfile.h"


// A track in the library is identified by a location and an id.
// The location is mandatory to identify the file, whereas the id
// only exists after the track has been inserted into the database.
//
// This class is intended to be used as a simple, almost immutable
// value object. Only the id can be set once.
class TrackRef final {
public:
    // Converts a TrackFile and an optional TrackId into a TrackRef. This
    // involves obtaining the file-related track properties from QFileInfo
    // (see above) and should used consciously! The file info is refreshed
    // implicitly if the canonical location if necessary.
    static TrackRef fromFileInfo(
            TrackFile fileInfo,
            TrackId id = TrackId()) {
        auto canonicalLocation = fileInfo.freshCanonicalLocation();
        // All properties of the file info are now considered fresh
        return TrackRef(
                fileInfo.location(),
                std::move(canonicalLocation),
                std::move(id));
    }

    // Default constructor
    TrackRef() {
        DEBUG_ASSERT(verifyConsistency());
    }
    // Regular copy constructor
    TrackRef(const TrackRef& other) = default;
    // Custom copy constructor:  Creates a copy of an existing TrackRef,
    // but overwrite the TrackId with a custom value.
    TrackRef(
            const TrackRef& other,
            TrackId id)
        : m_location(other.m_location),
          m_canonicalLocation(other.m_canonicalLocation),
          m_id(id) {
        DEBUG_ASSERT(verifyConsistency());
    }

    // The human-readable identifier of a track in Mixxx. The location is
    // immutable and the starting point for accessing a track's file.
    const QString& getLocation() const {
        return m_location;
    }
    bool hasLocation() const {
        return !getLocation().isEmpty();
    }

    // The unique identifier of a track's file at runtime and used
    // for caching. The canonical location is empty for inexistent
    // files.
    const QString& getCanonicalLocation() const {
        return m_canonicalLocation;
    }
    bool hasCanonicalLocation() const {
        return !getCanonicalLocation().isEmpty();
    }

    // The primary key of a track in the Mixxx library. The id must only
    // be set once after inserting into or after loading from the database.
    // Tracks that have not been stored in the database don't have an id.
    const TrackId& getId() const {
        return m_id;
    }
    bool hasId() const {
        return getId().isValid();
    }

    bool isValid() const {
        return hasId() || hasCanonicalLocation();
    }

protected:
    // Initializing constructor
    TrackRef(
            const QString& location,
            const QString& canonicalLocation,
            TrackId id = TrackId())
        : m_location(location),
          m_canonicalLocation(canonicalLocation),
          m_id(id) {
        DEBUG_ASSERT(verifyConsistency());
    }

private:
    // Checks if all class invariants are met
    bool verifyConsistency() const;

    QString m_location;
    QString m_canonicalLocation;
    TrackId m_id;
};

inline
bool operator==(const TrackRef& lhs, const TrackRef& rhs) {
    return (lhs.getId() == rhs.getId()) &&
            (lhs.getLocation() == rhs.getLocation()) &&
            (lhs.getCanonicalLocation() == rhs.getCanonicalLocation());
}

inline
bool operator!=(const TrackRef& lhs, const TrackRef& rhs) {
    return !(lhs == rhs);
}

Q_DECLARE_METATYPE(TrackRef)

std::ostream& operator<<(std::ostream& os, const TrackRef& trackRef);

QDebug operator<<(QDebug debug, const TrackRef& trackRef);

inline uint qHash(
        const TrackRef& key,
        uint seed = 0) {
    return qHash(
            key.getLocation(), seed) ^
            qHash(key.getId(), seed);
}