1 /*
2     Copyright (c) 2019, Michael Fisher <mfisher@kushview.net>
3 
4     Permission to use, copy, modify, and/or distribute this software for any
5     purpose with or without fee is hereby granted, provided that the above
6     copyright notice and this permission notice appear in all copies.
7 
8     THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9     WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10     MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11     ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12     WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13     ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 
17 #pragma once
18 
19 #include <map>
20 #include <string>
21 #include <lv2/lv2plug.in/ns/lv2core/lv2.h>
22 #include <lv2/lv2plug.in/ns/ext/urid/urid.h>
23 
24 namespace lvtk {
25 
26 /** Maintains a map of Strings/Symbols to integers
27 
28     This class also implements LV2 URID Map/Unmap features.  Plugin
29     implementations don't need to use this.  You can, however, use this in a
30     LV2 host to easily provide URID map/unmaping features to plugins.
31 
32     @headerfile lvtk/uri_directory.hpp
33     @ingroup urid
34  */
35 class URIDirectory
36 {
37 public:
38     /** Create an empty symbol map and initialized LV2 URID features */
URIDirectory()39     URIDirectory()
40     {
41         map_feature.URI    = LV2_URID__map;
42         map_data.handle    = (void*) this;
43         map_data.map       = &URIDirectory::_map;
44         map_feature.data   = &map_data;
45 
46         unmap_feature.URI  = LV2_URID__unmap;
47         unmap_data.handle  = this;
48         unmap_data.unmap   = _unmap;
49         unmap_feature.data = &unmap_data;
50     }
51 
~URIDirectory()52     ~URIDirectory()
53     {
54         clear();
55     }
56 
57     /** Map a symbol/uri to an unsigned integer
58         @param key The symbol to map
59         @returns A mapped URID, a return of 0 indicates failure */
map(const char * key)60     inline uint32_t map (const char* key)
61     {
62         if (! contains (key))
63         {
64             const uint32_t urid (1 + (uint32_t) mapped.size());
65             mapped [key] = urid;
66             unmapped [urid] = std::string (key);
67             return urid;
68         }
69 
70         return mapped [key];
71     }
72 
73     /** Containment test of a URI
74 
75         @param uri The URI to test
76         @returns True if found */
contains(const char * uri)77     inline bool contains (const char* uri) {
78         return mapped.find (uri) != mapped.end();
79     }
80 
81     /** Containment test of a URID
82 
83         @param urid The URID to test
84         @return True if found */
contains(uint32_t urid)85     inline bool contains (uint32_t urid) {
86         return unmapped.find (urid) != unmapped.end();
87     }
88 
89     /** Unmap an already mapped id to its symbol
90 
91         @param urid The URID to unmap
92         @return The previously mapped symbol or 0 if the urid isn't in the cache
93      */
unmap(uint32_t urid)94     inline const char* unmap (uint32_t urid) {
95         if (contains (urid))
96             return (const char*) unmapped [urid].c_str();
97         return "";
98     }
99 
100     /** Clear the URIDirectory */
clear()101     inline void clear()
102     {
103         mapped.clear();
104         unmapped.clear();
105     }
106 
107     /** @returns a LV2_Feature with LV2_URID_Map as the data member */
get_map_feature() const108     const LV2_Feature *const get_map_feature()      const { return &map_feature; }
109     /** @returns a LV2_Feature with LV2_URID_Unmap as the data member */
get_unmap_feature() const110     const LV2_Feature *const get_unmap_feature()    const { return &unmap_feature; }
111 
112 private:
113     std::map<std::string, uint32_t> mapped;
114     std::map<uint32_t, std::string> unmapped;
115 
116     LV2_Feature         map_feature;
117     LV2_URID_Map        map_data;
118     LV2_Feature         unmap_feature;
119     LV2_URID_Unmap      unmap_data;
120 
_map(LV2_URID_Map_Handle self,const char * uri)121     static uint32_t _map (LV2_URID_Map_Handle self, const char* uri) {
122         return (static_cast<URIDirectory*> (self))->map (uri);
123     }
124 
_unmap(LV2_URID_Unmap_Handle self,uint32_t urid)125     static const char* _unmap (LV2_URID_Unmap_Handle self, uint32_t urid) {
126         return (static_cast<URIDirectory*> (self))->unmap (urid);
127     }
128 };
129 
130 }
131