LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
PropertyCodeManager.cpp
Go to the documentation of this file.
1// Copyright 2002-2020 CEA LIST
2// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
6/***************************************************************************
7 * Copyright (C) 2004 by CEA LIST *
8 * *
9 ***************************************************************************/
10
11#include "PropertyCodeManager.h"
12#include "XmlPropertyReader.h"
14
15#include <QFile>
16
17#include <cmath>
18#include <iostream>
19#include <fstream>
20#include <sstream>
21#include <iterator>
22#include <typeinfo>
23
24using namespace std;
25
26namespace Lima
27{
28namespace Common
29{
30namespace PropertyCode
31{
32
33//utility functions for debug
34string hexString(const uint64_t x)
35{
36 ostringstream oss;
37 oss << hex << x;
38 return oss.str();
39}
40
41#ifdef uint128_t
42string hexString(const uint128_t x)
43{
44 ostringstream oss;
45 oss << hex << x;
46 return oss.str();
47}
48#endif
49
51{
52 friend class PropertyCodeManager;
53public:
58
59 std::map<std::string, PropertyManager> m_propertyManagers;
60
66 uint8_t computeNbBitsNeeded(uint64_t nbvalues) const;
67
77 LinguisticCode computeMask(uint8_t startBit,uint8_t nbBits) const;
78
79};
80
85
89
91 m_d(std::make_unique<PropertyCodeManagerPrivate>())
92{
93 m_d->m_propertyManagers = pcm.m_d->m_propertyManagers;
94}
95
97{
98 m_d->m_propertyManagers = pcm.m_d->m_propertyManagers;
99 return *this;
100}
101
102void PropertyCodeManager::readFromXmlFile(const std::string& filename)
103{
105#ifdef DEBUG_LP
106 LDEBUG << typeid(*this).name() << "PropertyCodeManager::readFromXmlFile" << filename;
107#endif
108
109#ifdef DEBUG_LP
110 LDEBUG << typeid(*this).name() << "PropertyCodeManager::readFromXmlFile before creating parser";
111#endif
112 //
113 // Create the reader object then parse the file and catch any exceptions
114 // that propogate out
115 //
116 XmlPropertyReader reader;
117#ifdef DEBUG_LP
118 LDEBUG << "PropertyCodeManager::readFromXmlFile before parsing";
119#endif
120 QFile file(filename.c_str());
121 if (!file.open(QIODevice::ReadOnly))
122 {
123 LIMA_EXCEPTION("PropertyCodeManager::readFromXmlFile Unable to open "
124 << filename.c_str());
125 }
126 if (!reader.parse(&file))
127 {
128 LIMA_EXCEPTION_SELECT("Error while parsing " << filename.c_str()
129 << " : " << reader.errorString(),
131 }
132#ifdef DEBUG_LP
133 LDEBUG << "PropertyCodeManager::readFromXmlFile parsed. before deleting parser";
134#endif
135 // Compute coding properties
136 uint8_t usedBits=0;
137
138 // compute data for properties
139 const auto& properties = reader.getProperties();
140#ifdef DEBUG_LP
141 LDEBUG << properties.size() << " properties read from xmlfile ";
142#endif
143 for (auto desc = properties.cbegin();
144 desc != properties.cend();
145 desc++)
146 {
147 // compute mask
148#ifdef DEBUG_LP
149 LDEBUG << "compute data for property " << desc->name;
150#endif
151 std::vector<std::string>::size_type nbvalues=desc->values.size() + 1;
152 uint8_t nbBits = m_d->computeNbBitsNeeded(nbvalues);
153#ifdef DEBUG_LP
154 LDEBUG << nbvalues << " values so use " << nbBits << " bits";
155#endif
156 LinguisticCode mask = m_d->computeMask(usedBits,nbBits);
157#ifdef DEBUG_LP
158 LDEBUG << "mask is " << mask.toHexString();
159#endif
160
161 // compute values
162 std::map<std::string,LinguisticCode> symbol2code;
163 symbol2code["NONE"] = L_NONE;
164 uint64_t i = 1;
165 for (auto valItr = desc->values.cbegin();
166 valItr != desc->values.cend();
167 valItr++)
168 {
169 LinguisticCode new_code = LinguisticCode::fromUInt(i) << usedBits;
170 symbol2code.insert(std::make_pair(*valItr, new_code));
171#ifdef DEBUG_LP
172 LDEBUG << *valItr << " => " << new_code.toHexString();
173#endif
174 i++;
175 }
176 usedBits += nbBits;
177 if (usedBits >= sizeof(LinguisticCode)*8)
178 {
179 std::runtime_error("Error: using more than the number of bits available.");
180 }
181 m_d->m_propertyManagers.insert(
182 std::make_pair(desc->name,
183 PropertyManager(desc->name, mask, mask, symbol2code)));
184 }
185
186 const auto& subproperties = reader.getSubProperties();
187#ifdef DEBUG_LP
188 LDEBUG << subproperties.size() << " subproperties read from file";
189#endif
190 for (const auto& desc: subproperties)
191 {
192#ifdef DEBUG_LP
193 LDEBUG << "compute data for subproperty " << desc.name << "of" << desc.parentName;
194#endif
195 const auto& parentProp = getPropertyManager(desc.parentName);
196 LinguisticCode parentmask = parentProp.getMask();
197
198 const auto& subvalues = desc.values;
199
200 // compute mask
201 // use enough bit to code the biggest subvalues set
202 uint64_t maxsubvalues=0;
203 for (auto it=subvalues.cbegin();
204 it!=subvalues.cend();
205 it++)
206 {
207 if (it->second.size()+1>maxsubvalues)
208 {
209 maxsubvalues=it->second.size()+1;
210 }
211 }
212 auto nbBits = m_d->computeNbBitsNeeded(maxsubvalues);
213#ifdef DEBUG_LP
214 LDEBUG << "maximum subvalues is " << maxsubvalues << " so use "
215 << nbBits << " bits";
216#endif
217 LinguisticCode emptynessmask = m_d->computeMask(usedBits,nbBits);
218 LinguisticCode mask = emptynessmask | parentmask;
219#ifdef DEBUG_LP
220 LDEBUG << "mask = " << mask.toHexString();
221 LDEBUG << "emptyness mask = " << emptynessmask.toHexString();
222#endif
223
224 // compute values
225 std::map<std::string,LinguisticCode> symbol2code;
226 symbol2code["NONE"] = L_NONE;
227 for (const auto& subvalue: subvalues)
228 {
229 LinguisticCode parentValue=parentProp.getPropertyValue(subvalue.first);
230#ifdef DEBUG_LP
231 LDEBUG << "value of" << subvalue.first << "is" << parentValue;
232#endif
233 if (parentValue == L_NONE)
234 {
235 LERROR << "parent value " << subvalue.first << " of subproperty "
236 << desc.name << " is unknown !";
237 }
238#ifdef DEBUG_LP
239 LDEBUG << "compute subvalues of " << subvalue.first << " ("
240 << parentValue.toHexString() << ")";
241#endif
242 symbol2code.insert(std::make_pair(string(subvalue.first)+"-NONE",
243 LinguisticCode(parentValue)));
244 uint64_t i = 1;
245 for (const auto& value: subvalue.second)
246 {
247 symbol2code.insert(std::make_pair(value, (LinguisticCode::fromUInt(i) << usedBits) | parentValue));
248#ifdef DEBUG_LP
249 LDEBUG << value << " => " << symbol2code[value].toHexString();
250#endif
251 i++;
252 }
253 }
254 m_d->m_propertyManagers.insert(std::make_pair(desc.name,
255 PropertyManager(desc.name,
256 mask,
257 emptynessmask,
258 symbol2code)));
259 usedBits += nbBits;
260
261 }
262
263#ifdef DEBUG_LP
264 LDEBUG << "have used " << usedBits << " bits to code all properties";
265#endif
266 if (usedBits > sizeof(LinguisticCode)*8)
267 {
268 LERROR << "needs" << usedBits
269 << "bits to code all properties !! Encoding may be Invalid !!";
270 throw std::runtime_error(
271 "Needs too much bits to code all properties !! Encoding would be Invalid !!");
272 }
273
274}
275
277 const std::string& propertyName) const
278{
279 auto it =m_d->m_propertyManagers.find(propertyName);
280 if (it == m_d->m_propertyManagers.end())
281 {
283 LERROR << "Ask for unknown property accessor:" << propertyName;
284 throw InvalidConfiguration();
285 }
286 return it->second;
287}
288
289const std::shared_ptr<PropertyAccessor> PropertyCodeManager::getPropertySetAccessor(
290 const std::set<std::string>& propertyNames) const
291{
292 ostringstream os;
293 std::copy(propertyNames.begin(), propertyNames.end(),
294 std::ostream_iterator<string>(os,":"));
295#ifdef DEBUG_LP
297 LDEBUG << "create propertysetAccessor for " << os.str();
298#endif
299 LinguisticCode propertySetMask;
300 LinguisticCode propertySetEmptyNessMask;
301 for (auto propItr = propertyNames.cbegin();
302 propItr != propertyNames.cend();
303 propItr++)
304 {
305 const auto& man = getPropertyManager(*propItr);
306 propertySetMask |= man.getMask();
307 propertySetEmptyNessMask |= man.getEmptyNessMask();
308 }
309#ifdef DEBUG_LP
310 LDEBUG << "propertysetMask is " << propertySetMask.toHexString();
311 LDEBUG << "propertysetEmptyNessMask is "
312 << propertySetEmptyNessMask.toHexString();
313#endif
314 return std::shared_ptr<PropertyAccessor>(
315 new PropertyAccessor(os.str(),
316 propertySetMask,
317 propertySetEmptyNessMask));
318}
319
321{
322 uint8_t nbBits=1;
323 for (uint64_t tmp=2; tmp < nbvalues; tmp*=2)
324 {
325 nbBits++;
326 }
327 if (nbBits > sizeof(LinguisticCode)*8)
328 {
330 LERROR << "Error: nb bits needed ("<<nbBits<<") is larger than sizeof LinguisticCode="
331 << sizeof(LinguisticCode)*8;
332 throw std::runtime_error(
333 "Error: nb bits needed is larger than sizeof LinguisticCode");
334 }
335 return nbBits;
336}
337
339 uint8_t nbBits) const
340{
341 if (startBit + nbBits > LinguisticCode::size())
342 {
344 LERROR << "Error: cannot compute mask. Would use more bits ("
345 << (startBit + nbBits) <<") than available ("
346 << sizeof(LinguisticCode)*8 << ")";
347 throw std::runtime_error("Error: cannot compute mask. Would use more bits than available");
348 }
349 LinguisticCode mask;
350 for (uint8_t currentBit = startBit;
351 currentBit < startBit + nbBits;
352 currentBit++)
353 {
354 mask |= (LinguisticCode::fromUInt(1) << currentBit);
355 }
356 return mask;
357}
358
360 std::string>& propValues) const
361{
362#ifdef DEBUG_LP
364#endif
365 LinguisticCode coded;
366#ifdef DEBUG_LP
367 LDEBUG << "encode";
368#endif
369 for (auto it = propValues.cbegin(); it != propValues.cend(); it++)
370 {
371 const auto& man = getPropertyManager(it->first);
372 man.getPropertyAccessor().writeValue(man.getPropertyValue(it->second),coded);
373 #ifdef DEBUG_LP
374 LDEBUG << it->first << " : " << it->second << " coded = " << coded.toHexString();
375 #endif
376 }
377 return coded;
378}
379
381 const std::string& symbolicCodeFile,
382 std::map<std::string,LinguisticCode>& conversionTable) const
383{
384#ifdef DEBUG_LP
386 LDEBUG << "convert Symbolic Code file " << symbolicCodeFile;
387#endif
388
389 //
390 // Create the reader object then parse the file and catch any exceptions
391 // that propogate out
392 //
393 SymbolicCodeXmlReader reader(*this, conversionTable);
394 QFile file(symbolicCodeFile.c_str());
395 if (!file.open(QIODevice::ReadOnly))
396 {
398 LERROR << "An error occurred Error: Cannot open " << symbolicCodeFile ;
399 throw std::runtime_error(
400 std::string("PropertyCodeManager::convertSymbolicCodes Unable to open ")
401 + symbolicCodeFile);
402 }
403 if (!reader.parse(&file))
404 {
406 LERROR << "PropertyCodeManager::convertSymbolicCodes An error occurred parsing"
407 << symbolicCodeFile
408 << ". Error: "
409 << reader.errorString() ;
410 throw XMLException(
411 std::string("Error while parsing " + symbolicCodeFile + " : "
412 + reader.errorString().toUtf8().constData()));
413 }
414}
415
416const std::map<std::string,PropertyManager>& PropertyCodeManager::getPropertyManagers() const
417{
418 return m_d->m_propertyManagers;
419}
420
422 const std::string& propertyName) const
423{
424 return getPropertyManager(propertyName).getPropertyAccessor();
425}
426
427} // PropertyCode
428} // Common
429} // Lima
#define LIMA_EXCEPTION(X)
This macro writes the message X to a previously configured error stream before throwing a LimaExcepti...
Definition LimaCommon.h:293
#define LDEBUG
Definition LimaCommon.h:157
#define LERROR
Definition LimaCommon.h:161
#define PROPERTYCODELOGINIT
Definition LimaCommon.h:213
#define LIMA_EXCEPTION_SELECT(X, Y)
This macro writes the message X to a previously configured error stream before throwing a Y exception...
Definition LimaCommon.h:306
#define L_NONE
Definition StdBitset.h:338
Provide function to read write and check a property.
std::map< std::string, PropertyManager > m_propertyManagers
uint8_t computeNbBitsNeeded(uint64_t nbvalues) const
Compute the number of bit needed to encode nbvalues.
LinguisticCode computeMask(uint8_t startBit, uint8_t nbBits) const
The mask of a property is an integer that show which bits are used.
PropertyCodeManagerPrivate(const PropertyCodeManagerPrivate &)=delete
PropertyCodeManagerPrivate & operator=(const PropertyCodeManagerPrivate &)=delete
Provide tools to parse a property file, and deal with the property coding system.
const std::shared_ptr< PropertyAccessor > getPropertySetAccessor(const std::set< std::string > &propertyNames) const
Get a PropertyAccessor associated to several properties.
void convertSymbolicCodes(const std::string &symbolicCodeFile, std::map< std::string, LinguisticCode > &conversionTable) const
Compute conversion of symbolic codes into linguisticCode and append them into the given map.
const std::map< std::string, PropertyManager > & getPropertyManagers() const
Get the map of all PropertyManagers.
const PropertyManager & getPropertyManager(const std::string &propertyName) const
Get the PropertyManager associated to a property.
void readFromXmlFile(const std::string &filename)
This functions should be called once, just after creation.
PropertyCodeManager & operator=(const PropertyCodeManager &)
const PropertyAccessor & getPropertyAccessor(const std::string &propertyName) const
Get the PropertyAccessor associated to a property.
LinguisticCode encode(const std::map< std::string, std::string > &propValues) const
Compute the code corresponding to given the properties/values.
Provide tools to manage a specific property.
const PropertyAccessor & getPropertyAccessor() const
give the corresponding PropertyAccessor
const std::vector< PropertyDescription > & getProperties()
const std::vector< SubPropertyDescription > & getSubProperties()
Use this exception to signal an error in one of the configuration files.
Definition LimaCommon.h:345
std::string toHexString() const
Definition StdBitset.h:135
static std::size_t size() noexcept
Definition StdBitset.h:94
static LinguisticCode fromUInt(uint64_t v)
Definition StdBitset.h:65
Throw this exception when encountering problems with XML files opening or parsing.
Definition LimaCommon.h:470
bool parse(QIODevice *device)
string hexString(const uint64_t x)
NAUTITIA.
STL namespace.