Fixup prev commit (LV2 X11 UI) -- #7837
[ardour.git] / libs / ardour / port_set.cc
1 /*
2  * Copyright (C) 2006-2012 David Robillard <d@drobilla.net>
3  * Copyright (C) 2008-2011 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
5  * Copyright (C) 2014-2015 Robin Gareus <robin@gareus.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <string>
23
24 #include "ardour/audio_port.h"
25 #include "ardour/midi_port.h"
26 #include "ardour/port.h"
27 #include "ardour/port_set.h"
28
29 using std::string;
30
31 namespace ARDOUR {
32
33 PortSet::PortSet()
34 {
35         for (size_t i=0; i < DataType::num_types; ++i)
36                 _ports.push_back( PortVec() );
37 }
38
39 static bool sort_ports_by_name (boost::shared_ptr<Port> a, boost::shared_ptr<Port> b)
40 {
41         string aname (a->name());
42         string bname (b->name());
43
44         string::size_type last_digit_position_a = aname.size();
45         string::reverse_iterator r_iterator = aname.rbegin();
46
47         while (r_iterator!= aname.rend() && Glib::Unicode::isdigit(*r_iterator)) {
48                 r_iterator++;
49                 last_digit_position_a--;
50         }
51
52         string::size_type last_digit_position_b = bname.size();
53         r_iterator = bname.rbegin();
54
55         while (r_iterator != bname.rend() && Glib::Unicode::isdigit(*r_iterator)) {
56                 r_iterator++;
57                 last_digit_position_b--;
58         }
59
60         // if some of the names don't have a number as posfix, compare as strings
61
62         if (last_digit_position_a == aname.size() || last_digit_position_b == bname.size()) {
63                 return aname < bname;
64         }
65
66         const std::string       prefix_a = aname.substr(0, last_digit_position_a - 1);
67         const unsigned int      posfix_a = std::atoi(aname.substr(last_digit_position_a, aname.size() - last_digit_position_a).c_str());
68         const std::string       prefix_b = bname.substr(0, last_digit_position_b - 1);
69         const unsigned int      posfix_b = std::atoi(bname.substr(last_digit_position_b, bname.size() - last_digit_position_b).c_str());
70
71         if (prefix_a != prefix_b) {
72                 return aname < bname;
73         } else {
74                 return posfix_a < posfix_b;
75         }
76 }
77
78
79 static bool sort_ports_by_type_and_name (boost::shared_ptr<Port> a, boost::shared_ptr<Port> b)
80 {
81         if (a->type() != b->type()) {
82                 return a->type() < b->type();
83         }
84
85         return sort_ports_by_name (a, b);
86 }
87
88 void
89 PortSet::add (boost::shared_ptr<Port> port)
90 {
91         PortVec& v = _ports[port->type()];
92
93         v.push_back(port);
94         _all_ports.push_back(port);
95
96         sort(v.begin(), v.end(), sort_ports_by_name);
97         sort(_all_ports.begin(), _all_ports.end(), sort_ports_by_type_and_name);
98
99         _count.set(port->type(), _count.get(port->type()) + 1);
100         assert(_count.get(port->type()) == _ports[port->type()].size());
101 }
102
103 bool
104 PortSet::remove (boost::shared_ptr<Port> port)
105 {
106         PortVec::iterator i = find(_all_ports.begin(), _all_ports.end(), port);
107         if (i != _all_ports.end()) {
108                 _all_ports.erase(i);
109         }
110
111         for (std::vector<PortVec>::iterator l = _ports.begin(); l != _ports.end(); ++l) {
112                 PortVec::iterator i = find(l->begin(), l->end(), port);
113                 if (i != l->end()) {
114                         l->erase(i);
115                         _count.set(port->type(), _count.get(port->type()) - 1);
116                         return true;
117                 }
118         }
119
120         return false;
121 }
122
123 /** Get the total number of ports (of all types) in the PortSet
124  */
125 size_t
126 PortSet::num_ports() const
127 {
128         return _all_ports.size();
129 }
130
131 bool
132 PortSet::contains (boost::shared_ptr<const Port> port) const
133 {
134         return find(_all_ports.begin(), _all_ports.end(), port) != _all_ports.end();
135 }
136
137 boost::shared_ptr<Port>
138 PortSet::port(size_t n) const
139 {
140         assert(n < _all_ports.size());
141         return _all_ports[n];
142 }
143
144 boost::shared_ptr<Port>
145 PortSet::port(DataType type, size_t n) const
146 {
147         if (type == DataType::NIL) {
148                 return port(n);
149         } else {
150                 const PortVec& v = _ports[type];
151                 if (n < v.size()) {
152                         return v[n];
153                 }
154         }
155         return boost::shared_ptr<Port>();
156 }
157
158 boost::shared_ptr<AudioPort>
159 PortSet::nth_audio_port(size_t n) const
160 {
161         return boost::dynamic_pointer_cast<AudioPort> (port (DataType::AUDIO, n));
162 }
163
164 boost::shared_ptr<MidiPort>
165 PortSet::nth_midi_port(size_t n) const
166 {
167         return boost::dynamic_pointer_cast<MidiPort> (port (DataType::MIDI, n));
168 }
169
170 void
171 PortSet::clear()
172 {
173         _ports.clear();
174         _all_ports.clear();
175 }
176
177 } // namepace ARDOUR