KiCad PCB EDA Suite
kiid.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2020 Ian McInerney <ian.s.mcinerney@ieee.org>
5  * Copyright (C) 2007-2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
6  * Copyright (C) 1992-2020 KiCad Developers, see CHANGELOG.TXT for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <common.h> // AsLegacyTimestampString, AsString
27 #include <kiid.h>
28 
29 #include <boost/uuid/uuid_generators.hpp>
30 #include <boost/uuid/uuid_io.hpp>
31 #include <boost/functional/hash.hpp>
32 
33 #if BOOST_VERSION >= 106700
34 #include <boost/uuid/entropy_error.hpp>
35 #endif
36 
37 #include <wx/log.h>
38 
39 
40 // Create only once, as seeding is *very* expensive
41 static boost::uuids::random_generator randomGenerator;
42 
43 // These don't have the same performance penalty, but might as well be consistent
44 static boost::uuids::string_generator stringGenerator;
45 static boost::uuids::nil_generator nilGenerator;
46 
47 // Global nil reference
48 KIID niluuid( 0 );
49 
50 
51 // For static initialization
53 {
54  static KIID nil( 0 );
55  return nil;
56 }
57 
58 
60 {
62 
63 #if BOOST_VERSION >= 106700
64  try
65  {
66 #endif
67 
69 
70 #if BOOST_VERSION >= 106700
71  }
72  catch( const boost::uuids::entropy_error& )
73  {
74  wxLogFatalError( "A Boost UUID entropy exception was thrown in %s:%s.",
75  __FILE__, __FUNCTION__ );
76  }
77 #endif
78 }
79 
80 
81 KIID::KIID( int null ) : m_uuid( nilGenerator() ), m_cached_timestamp( 0 )
82 {
83  wxASSERT( null == 0 );
84 }
85 
86 
87 KIID::KIID( const wxString& aString ) : m_uuid(), m_cached_timestamp( 0 )
88 {
89  if( aString.length() == 8 )
90  {
91  // A legacy-timestamp-based UUID has only the last 4 octets filled in.
92  // Convert them individually to avoid stepping in the little-endian/big-endian
93  // doo-doo.
94  for( int i = 0; i < 4; ++i )
95  {
96  wxString octet = aString.substr( i * 2, 2 );
97  m_uuid.data[i + 12] = strtol( octet.data(), NULL, 16 );
98  }
99 
100  m_cached_timestamp = strtol( aString.c_str(), NULL, 16 );
101  }
102  else
103  {
104  try
105  {
106  m_uuid = stringGenerator( aString.wc_str() );
107 
108  if( IsLegacyTimestamp() )
109  m_cached_timestamp = strtol( aString.substr( 28 ).c_str(), NULL, 16 );
110  }
111  catch( ... )
112  {
113  // Failed to parse string representation; best we can do is assign a new
114  // random one.
115 #if BOOST_VERSION >= 106700
116  try
117  {
118 #endif
119 
121 
122 #if BOOST_VERSION >= 106700
123  }
124  catch( const boost::uuids::entropy_error& )
125  {
126  wxLogFatalError( "A Boost UUID entropy exception was thrown in %s:%s.",
127  __FILE__, __FUNCTION__ );
128  }
129 #endif
130  }
131  }
132 }
133 
134 
135 bool KIID::SniffTest( const wxString& aCandidate )
136 {
137  static wxString niluuidStr = niluuid.AsString();
138 
139  if( aCandidate.Length() != niluuidStr.Length() )
140  return false;
141 
142  for( wxChar c : aCandidate )
143  {
144  if( c >= '0' && c <= '9' )
145  continue;
146 
147  if( c >= 'a' && c <= 'f' )
148  continue;
149 
150  if( c >= 'A' && c <= 'F' )
151  continue;
152 
153  if( c == '-' )
154  continue;
155 
156  return false;
157  }
158 
159  return true;
160 }
161 
162 
163 KIID::KIID( timestamp_t aTimestamp )
164 {
165  m_cached_timestamp = aTimestamp;
166 
167  // A legacy-timestamp-based UUID has only the last 4 octets filled in.
168  // Convert them individually to avoid stepping in the little-endian/big-endian
169  // doo-doo.
170  wxString str = AsLegacyTimestampString();
171 
172  for( int i = 0; i < 4; ++i )
173  {
174  wxString octet = str.substr( i * 2, 2 );
175  m_uuid.data[i + 12] = strtol( octet.data(), NULL, 16 );
176  }
177 }
178 
179 
181 {
182  return !m_uuid.data[8] && !m_uuid.data[9] && !m_uuid.data[10] && !m_uuid.data[11];
183 }
184 
185 
187 {
188  return m_cached_timestamp;
189 }
190 
191 
192 size_t KIID::Hash() const
193 {
194  size_t hash = 0;
195 
196  // Note: this is NOT little-endian/big-endian safe, but as long as it's just used
197  // at runtime it won't matter.
198 
199  for( int i = 0; i < 4; ++i )
200  boost::hash_combine( hash, reinterpret_cast<const uint32_t*>( m_uuid.data )[i] );
201 
202  return hash;
203 }
204 
205 
206 void KIID::Clone( const KIID& aUUID )
207 {
208  m_uuid = aUUID.m_uuid;
210 }
211 
212 
213 wxString KIID::AsString() const
214 {
215  return boost::uuids::to_string( m_uuid );
216 }
217 
218 
220 {
221  return wxString::Format( "%8.8lX", (unsigned long) AsLegacyTimestamp() );
222 }
223 
224 
226 {
227  if( !IsLegacyTimestamp() )
228  return;
229 
230  m_cached_timestamp = 0;
232 }
233 
234 
235 KIID_PATH::KIID_PATH( const wxString& aString )
236 {
237  for( const wxString& pathStep : wxSplit( aString, '/' ) )
238  {
239  if( !pathStep.empty() )
240  emplace_back( KIID( pathStep ) );
241  }
242 }
243 
244 
245 wxString KIID_PATH::AsString() const
246 {
247  wxString path;
248 
249  for( const KIID& pathStep : *this )
250  path += '/' + pathStep.AsString();
251 
252  return path;
253 }
KIID niluuid(0)
KIID()
Definition: kiid.cpp:59
wxString AsString() const
Definition: kiid.cpp:213
boost::uuids::uuid m_uuid
Definition: kiid.h:92
static void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
Definition: hash_eda.h:67
bool IsLegacyTimestamp() const
Definition: kiid.cpp:180
timestamp_t m_cached_timestamp
Definition: kiid.h:94
static boost::uuids::nil_generator nilGenerator
Definition: kiid.cpp:45
Definition: kiid.h:44
size_t Hash() const
Definition: kiid.cpp:192
#define NULL
KIID_PATH()
Definition: kiid.h:108
timestamp_t AsLegacyTimestamp() const
Definition: kiid.cpp:186
static bool SniffTest(const wxString &aCandidate)
Definition: kiid.cpp:135
static boost::uuids::random_generator randomGenerator
Definition: kiid.cpp:41
void ConvertTimestampToUuid()
Change an existing time stamp based UUID into a true UUID.
Definition: kiid.cpp:225
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
uint32_t timestamp_t
timestamp_t is our type to represent unique IDs for all kinds of elements; historically simply the ti...
Definition: kiid.h:32
void Clone(const KIID &aUUID)
Definition: kiid.cpp:206
wxString AsLegacyTimestampString() const
Definition: kiid.cpp:219
wxString AsString() const
Definition: kiid.cpp:245
The common library.
KIID & NilUuid()
Definition: kiid.cpp:52
static boost::uuids::string_generator stringGenerator
Definition: kiid.cpp:44