summaryrefslogtreecommitdiff
path: root/libs/ardour/ardour/port_set.h
blob: fce36279674c1784bda063cbbe52f7a4d79a4c9e (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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
    Copyright (C) 2006 Paul Davis

    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 __ardour_port_set_h__
#define __ardour_port_set_h__

#include <vector>
#include "ardour/chan_count.h"
#include <boost/utility.hpp>

namespace ARDOUR {

class Port;
class AudioPort;
class MidiPort;

/** An ordered list of Ports, possibly of various types.
 *
 * This allows access to all the ports as a list, ignoring type, or accessing
 * the nth port of a given type.  Note that port(n) and nth_audio_port(n) may
 * NOT return the same port.
 *
 * Each port is held twice; once in a per-type vector of vectors (_ports)
 * and once in a vector of all port (_all_ports).  This is to speed up the
 * fairly common case of iterating over all ports.
 */
class LIBARDOUR_API PortSet : public boost::noncopyable {
public:
	PortSet();

	size_t num_ports() const;
	size_t num_ports(DataType type) const { return _ports[type].size(); }

	void add (boost::shared_ptr<Port> port);
	bool remove (boost::shared_ptr<Port> port);

	/** nth port
	 * @param index port index
	 */
	boost::shared_ptr<Port> port(size_t index) const;

	/** nth port of type @a t, or nth port if t = NIL
	 * @param t data type
	 * @param index port index
	 */
	boost::shared_ptr<Port> port(DataType t, size_t index) const;

	boost::shared_ptr<AudioPort> nth_audio_port(size_t n) const;

	boost::shared_ptr<MidiPort> nth_midi_port(size_t n) const;

	bool contains (boost::shared_ptr<const Port> port) const;

	/** Remove all ports from the PortSet.  Ports are not deregistered with
	 * the engine, it's the caller's responsibility to not leak here!
	 */
	void clear();

	const ChanCount& count() const { return _count; }

	bool empty() const { return (_count.n_total() == 0); }

	template<typename PS, typename P>
	class iterator_base {
	public:
		boost::shared_ptr<P> operator*()  { return _set.port(_type, _index); }
		boost::shared_ptr<P> operator->() { return _set.port(_type, _index); }
		iterator_base<PS,P>& operator++() { ++_index; return *this; } // yes, prefix only
		bool operator==(const iterator_base<PS,P>& other) { return (_index == other._index); }
		bool operator!=(const iterator_base<PS,P>& other) { return (_index != other._index); }

	private:
		friend class PortSet;

		iterator_base<PS,P>(PS& list, DataType type, size_t index)
			: _set(list), _type(type), _index(index) {}

		PS&      _set;
		DataType _type; ///< Ignored if NIL (to iterator over entire set)
		size_t   _index;
	};

	typedef iterator_base<PortSet, Port>             iterator;
	typedef iterator_base<const PortSet, const Port> const_iterator;

	iterator begin(DataType type = DataType::NIL) {
		return iterator(*this, type, 0);
	}

	iterator end(DataType type = DataType::NIL) {
		return iterator(*this, type,
			(type == DataType::NIL) ? _count.n_total() : _count.get(type));
	}

	const_iterator begin(DataType type = DataType::NIL) const {
		return const_iterator(*this, type, 0);
	}

	const_iterator end(DataType type = DataType::NIL) const {
		return const_iterator(*this, type,
			(type == DataType::NIL) ? _count.n_total() : _count.get(type));
	}

	class audio_iterator {
	public:
		boost::shared_ptr<AudioPort> operator*()  { return _set.nth_audio_port(_index); }
		boost::shared_ptr<AudioPort> operator->() { return _set.nth_audio_port(_index); }
		audio_iterator& operator++() { ++_index; return *this; } // yes, prefix only
		bool operator==(const audio_iterator& other) { return (_index == other._index); }
		bool operator!=(const audio_iterator& other) { return (_index != other._index); }

	private:
		friend class PortSet;

		audio_iterator(PortSet& list, size_t index) : _set(list), _index(index) {}

		PortSet& _set;
		size_t   _index;
	};

	audio_iterator audio_begin() { return audio_iterator(*this, 0); }
	audio_iterator audio_end()   { return audio_iterator(*this, _count.n_audio()); }

private:
	typedef std::vector<boost::shared_ptr<Port> > PortVec;

	// Vector of vectors, indexed by DataType::to_index()
	std::vector<PortVec> _ports;
	// All ports in _ports in one vector, to speed some operations
	PortVec _all_ports;

	ChanCount _count;
};


} // namespace ARDOUR

#endif // __ardour_port_set_h__