Sync with 5.3.0
[deliverable/titan.core.git] / core / Float.cc
CommitLineData
970ed795
EL
1///////////////////////////////////////////////////////////////////////////////
2// Copyright (c) 2000-2014 Ericsson Telecom AB
3// All rights reserved. This program and the accompanying materials
4// are made available under the terms of the Eclipse Public License v1.0
5// which accompanies this distribution, and is available at
6// http://www.eclipse.org/legal/epl-v10.html
7///////////////////////////////////////////////////////////////////////////////
8#include <string.h>
9#include <math.h>
10#include <float.h>
11
12#include "../common/memory.h"
13#include "Float.hh"
14#include "Types.h"
15#include "Param_Types.hh"
16#include "Optional.hh"
17#include "Logger.hh"
18#include "Error.hh"
19#include "Encdec.hh"
20#include "RAW.hh"
21#include "BER.hh"
22#include "Charstring.hh"
23#include "Addfunc.hh"
24#include "XmlReader.hh"
25
26#include "../common/dbgnew.hh"
27
28
29#ifndef INFINITY
30#define INFINITY (DBL_MAX*DBL_MAX)
31#endif
32const FLOAT PLUS_INFINITY(INFINITY);
33const FLOAT MINUS_INFINITY(-INFINITY);
34
35#ifdef NAN
36const FLOAT NOT_A_NUMBER(NAN);
37#else
38const FLOAT NOT_A_NUMBER((double)PLUS_INFINITY+(double)MINUS_INFINITY);
39// The casts ensure that FLOAT::operator+ is not called
40#endif
41
42
43static inline void log_float(double float_val)
44{
45 if ( (float_val > -MAX_DECIMAL_FLOAT && float_val <= -MIN_DECIMAL_FLOAT)
46 || (float_val >= MIN_DECIMAL_FLOAT && float_val < MAX_DECIMAL_FLOAT)
47 || (float_val == 0.0))
48 TTCN_Logger::log_event("%f", float_val);
49 else if(float_val==INFINITY)
50 TTCN_Logger::log_event_str("infinity");
51 else if(float_val==-INFINITY)
52 TTCN_Logger::log_event_str("-infinity");
53 else if(float_val!=float_val)
54 TTCN_Logger::log_event_str("not_a_number");
55 else TTCN_Logger::log_event("%e", float_val);
56}
57
58// float value class
59
60FLOAT::FLOAT()
61{
62 bound_flag = FALSE;
63}
64
65FLOAT::FLOAT(double other_value)
66{
67 bound_flag = TRUE;
68 float_value = other_value;
69}
70
71FLOAT::FLOAT(const FLOAT& other_value)
72: Base_Type(other_value)
73{
74 other_value.must_bound("Copying an unbound float value.");
75 bound_flag = TRUE;
76 float_value = other_value.float_value;
77}
78
79void FLOAT::clean_up()
80{
81 bound_flag = FALSE;
82}
83
84FLOAT& FLOAT::operator=(double other_value)
85{
86 bound_flag = TRUE;
87 float_value = other_value;
88 return *this;
89}
90
91FLOAT& FLOAT::operator=(const FLOAT& other_value)
92{
93 other_value.must_bound("Assignment of an unbound float value.");
94 bound_flag = TRUE;
95 float_value = other_value.float_value;
96 return *this;
97}
98
99double FLOAT::operator+() const
100{
101 must_bound("Unbound float operand of unary + operator.");
102 return float_value;
103}
104
105double FLOAT::operator-() const
106{
107 must_bound("Unbound float operand of unary - operator (negation).");
108 return -float_value;
109}
110
111bool FLOAT::is_special(double flt_val)
112{
113 return ( (flt_val!=flt_val) || (flt_val==INFINITY) || (flt_val==-INFINITY) );
114}
115
116void FLOAT::check_numeric(double flt_val, const char *err_msg_begin)
117{
118 if (is_special(flt_val)) {
119 TTCN_error("%s must be a numeric value instead of %g",
120 err_msg_begin, flt_val);
121 }
122}
123
124double FLOAT::operator+(double other_value) const
125{
126 must_bound("Unbound left operand of float addition.");
127 check_numeric(float_value, "Left operand of float addition");
128 check_numeric(other_value, "Right operand of float addition");
129 return float_value + other_value;
130}
131
132double FLOAT::operator+(const FLOAT& other_value) const
133{
134 must_bound("Unbound left operand of float addition.");
135 other_value.must_bound("Unbound right operand of float addition.");
136 check_numeric(float_value, "Left operand of float addition");
137 check_numeric(other_value.float_value, "Right operand of float addition");
138 return float_value + other_value.float_value;
139}
140
141double FLOAT::operator-(double other_value) const
142{
143 must_bound("Unbound left operand of float subtraction.");
144 check_numeric(float_value, "Left operand of float subtraction");
145 check_numeric(other_value, "Right operand of float subtraction");
146 return float_value - other_value;
147}
148
149double FLOAT::operator-(const FLOAT& other_value) const
150{
151 must_bound("Unbound left operand of float subtraction.");
152 other_value.must_bound("Unbound right operand of float subtraction.");
153 check_numeric(float_value, "Left operand of float subtraction");
154 check_numeric(other_value.float_value, "Right operand of float subtraction");
155 return float_value - other_value.float_value;
156}
157
158double FLOAT::operator*(double other_value) const
159{
160 must_bound("Unbound left operand of float multiplication.");
161 check_numeric(float_value, "Left operand of float multiplication");
162 check_numeric(other_value, "Right operand of float multiplication");
163 return float_value * other_value;
164}
165
166double FLOAT::operator*(const FLOAT& other_value) const
167{
168 must_bound("Unbound left operand of float multiplication.");
169 other_value.must_bound("Unbound right operand of float multiplication.");
170 check_numeric(float_value, "Left operand of float multiplication");
171 check_numeric(other_value.float_value, "Right operand of float multiplication");
172 return float_value * other_value.float_value;
173}
174
175double FLOAT::operator/(double other_value) const
176{
177 must_bound("Unbound left operand of float division.");
178 check_numeric(float_value, "Left operand of float division");
179 check_numeric(other_value, "Right operand of float division");
180 if (other_value == 0.0) TTCN_error("Float division by zero.");
181 return float_value / other_value;
182}
183
184double FLOAT::operator/(const FLOAT& other_value) const
185{
186 must_bound("Unbound left operand of float division.");
187 other_value.must_bound("Unbound right operand of float division.");
188 check_numeric(float_value, "Left operand of float division");
189 check_numeric(other_value.float_value, "Right operand of float division");
190 if (other_value.float_value == 0.0) TTCN_error("Float division by zero.");
191 return float_value / other_value.float_value;
192}
193
194boolean FLOAT::operator==(double other_value) const
195{
196 must_bound("Unbound left operand of float comparison.");
197 return float_value == other_value;
198}
199
200boolean FLOAT::operator==(const FLOAT& other_value) const
201{
202 must_bound("Unbound left operand of float comparison.");
203 other_value.must_bound("Unbound right operand of float comparison.");
204 return float_value == other_value.float_value;
205}
206
207boolean FLOAT::operator<(double other_value) const
208{
209 must_bound("Unbound left operand of float comparison.");
210 return float_value < other_value;
211}
212
213boolean FLOAT::operator<(const FLOAT& other_value) const
214{
215 must_bound("Unbound left operand of float comparison.");
216 other_value.must_bound("Unbound right operand of float comparison.");
217 return float_value < other_value.float_value;
218}
219
220boolean FLOAT::operator>(double other_value) const
221{
222 must_bound("Unbound left operand of float comparison.");
223 return float_value > other_value;
224}
225
226boolean FLOAT::operator>(const FLOAT& other_value) const
227{
228 must_bound("Unbound left operand of float comparison.");
229 other_value.must_bound("Unbound right operand of float comparison.");
230 return float_value > other_value.float_value;
231}
232
233FLOAT::operator double() const
234{
235 must_bound("Using the value of an unbound float variable.");
236 return float_value;
237}
238
239void FLOAT::log() const
240{
241 if (bound_flag) log_float(float_value);
242 else TTCN_Logger::log_event_unbound();
243}
244
245void FLOAT::set_param(Module_Param& param) {
246 param.basic_check(Module_Param::BC_VALUE, "float value");
247 if (param.get_type()!=Module_Param::MP_Float) param.type_error("float value");
248 bound_flag = TRUE;
249 float_value = param.get_float();
250}
251
252void FLOAT::encode_text(Text_Buf& text_buf) const
253{
254 must_bound("Text encoder: Encoding an unbound float value.");
255 text_buf.push_double(float_value);
256}
257
258void FLOAT::decode_text(Text_Buf& text_buf)
259{
260 bound_flag = TRUE;
261 float_value = text_buf.pull_double();
262}
263
264void FLOAT::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
265 TTCN_EncDec::coding_t p_coding, ...) const
266{
267 va_list pvar;
268 va_start(pvar, p_coding);
269 switch(p_coding) {
270 case TTCN_EncDec::CT_BER: {
271 TTCN_EncDec_ErrorContext ec("While BER-encoding type '%s': ", p_td.name);
272 unsigned BER_coding=va_arg(pvar, unsigned);
273 BER_encode_chk_coding(BER_coding);
274 ASN_BER_TLV_t *tlv=BER_encode_TLV(p_td, BER_coding);
275 tlv->put_in_buffer(p_buf);
276 ASN_BER_TLV_t::destruct(tlv);
277 break;}
278 case TTCN_EncDec::CT_RAW: {
279 TTCN_EncDec_ErrorContext ec("While RAW-encoding type '%s': ", p_td.name);
280 if(!p_td.raw)
281 TTCN_EncDec_ErrorContext::error_internal
282 ("No RAW descriptor available for type '%s'.", p_td.name);
283 RAW_enc_tr_pos rp;
284 rp.level=0;
285 rp.pos=NULL;
286 RAW_enc_tree root(TRUE,NULL,&rp,1,p_td.raw);
287 RAW_encode(p_td, root);
288 root.put_to_buf(p_buf);
289 break;}
290 case TTCN_EncDec::CT_XER: {
291 TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name);
292 unsigned XER_coding=va_arg(pvar, unsigned);
af710487 293 XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0);
970ed795
EL
294 break;}
295 case TTCN_EncDec::CT_JSON: {
296 TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name);
297 if(!p_td.json)
298 TTCN_EncDec_ErrorContext::error_internal
299 ("No JSON descriptor available for type '%s'.", p_td.name);
300 JSON_Tokenizer tok(va_arg(pvar, int) != 0);
301 JSON_encode(p_td, tok);
302 p_buf.put_s(tok.get_buffer_length(), (const unsigned char*)tok.get_buffer());
303 break;}
304 default:
305 TTCN_error("Unknown coding method requested to encode type '%s'",
306 p_td.name);
307 }
308 va_end(pvar);
309}
310
311void FLOAT::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
312 TTCN_EncDec::coding_t p_coding, ...)
313{
314 va_list pvar;
315 va_start(pvar, p_coding);
316 switch(p_coding) {
317 case TTCN_EncDec::CT_BER: {
318 TTCN_EncDec_ErrorContext ec("While BER-decoding type '%s': ", p_td.name);
319 unsigned L_form=va_arg(pvar, unsigned);
320 ASN_BER_TLV_t tlv;
321 BER_decode_str2TLV(p_buf, tlv, L_form);
322 BER_decode_TLV(p_td, tlv, L_form);
323 if(tlv.isComplete) p_buf.increase_pos(tlv.get_len());
324 break;}
325 case TTCN_EncDec::CT_RAW: {
326 TTCN_EncDec_ErrorContext ec("While RAW-decoding type '%s': ", p_td.name);
327 if(!p_td.raw)
328 TTCN_EncDec_ErrorContext::error_internal
329 ("No RAW descriptor available for type '%s'.", p_td.name);
330 raw_order_t order;
331 switch(p_td.raw->top_bit_order){
332 case TOP_BIT_LEFT:
333 order=ORDER_LSB;
334 break;
335 case TOP_BIT_RIGHT:
336 default:
337 order=ORDER_MSB;
338 }
339 if(RAW_decode(p_td, p_buf, p_buf.get_len()*8, order)<0)
340 ec.error(TTCN_EncDec::ET_INCOMPL_MSG,
341 "Can not decode type '%s', because invalid or incomplete"
342 " message was received"
343 , p_td.name);
344 break;}
345 case TTCN_EncDec::CT_XER: {
af710487 346 TTCN_EncDec_ErrorContext ec("While XER-decoding type '%s': ", p_td.name);
970ed795
EL
347 unsigned XER_coding=va_arg(pvar, unsigned);
348 XmlReaderWrap reader(p_buf);
349 for (int success = reader.Read(); success==1; success=reader.Read()) {
350 int type = reader.NodeType();
351 if (type==XML_READER_TYPE_ELEMENT)
352 break;
353 }
af710487 354 XER_decode(*p_td.xer, reader, XER_coding, 0);
970ed795
EL
355 size_t bytes = reader.ByteConsumed();
356 p_buf.set_pos(bytes);
357 break;}
358 case TTCN_EncDec::CT_JSON: {
359 TTCN_EncDec_ErrorContext ec("While JSON-decoding type '%s': ", p_td.name);
360 if(!p_td.json)
361 TTCN_EncDec_ErrorContext::error_internal
362 ("No JSON descriptor available for type '%s'.", p_td.name);
363 JSON_Tokenizer tok((const char*)p_buf.get_data(), p_buf.get_len());
364 if(JSON_decode(p_td, tok, false)<0)
365 ec.error(TTCN_EncDec::ET_INCOMPL_MSG,
366 "Can not decode type '%s', because invalid or incomplete"
367 " message was received"
368 , p_td.name);
369 p_buf.set_pos(tok.get_buf_pos());
370 break;}
371 default:
372 TTCN_error("Unknown coding method requested to decode type '%s'",
373 p_td.name);
374 }
375 va_end(pvar);
376}
377
378ASN_BER_TLV_t*
379FLOAT::BER_encode_TLV(const TTCN_Typedescriptor_t& p_td,
380 unsigned p_coding) const
381{
382 BER_chk_descr(p_td);
383 ASN_BER_TLV_t *new_tlv=BER_encode_chk_bound(is_bound());
384 if(!new_tlv) {
385 if(float_value==0.0) {
386 new_tlv=ASN_BER_TLV_t::construct();
387 // nothing to do, Vlen is 0
388 }
389 /* +Infinity */
390 else if(float_value==(double)INFINITY) { // INFINITY may be float => cast
391 new_tlv=ASN_BER_TLV_t::construct(1, NULL);
392 new_tlv->V.str.Vstr[0]=0x40;
393 }
394 /* -Infinity */
395 else if(float_value==-(double)INFINITY) {
396 new_tlv=ASN_BER_TLV_t::construct(1, NULL);
397 new_tlv->V.str.Vstr[0]=0x41;
398 }
399 else if(isnan((double)float_value)) {
400 TTCN_EncDec_ErrorContext::error_internal("Value is NaN.");
401 }
402 else {
403 new_tlv=ASN_BER_TLV_t::construct();
404 double mantissa, exponent;
405 exponent=floor(log10(fabs(float_value)))+1.0-DBL_DIG;
406 mantissa=floor(float_value*pow(10.0,-exponent)+0.5);
407 if(mantissa)while(!fmod(mantissa,10.0))mantissa/=10.0,exponent+=1.0;
408 /** \todo review
409 gcc 2.95:
410 in mprintf below:
411 warning: `.' not followed by `*' or digit in format
412 */
413 new_tlv->V.str.Vstr=(unsigned char*)
414 mprintf("\x03%.f.E%s%.0f", mantissa, exponent==0.0?"+":"", exponent);
415 new_tlv->V.str.Vlen=1+strlen((const char*)&new_tlv->V.str.Vstr[1]);
416 }
417 }
418 new_tlv=ASN_BER_V2TLV(new_tlv, p_td, p_coding);
419 return new_tlv;
420}
421
422boolean FLOAT::BER_decode_TLV(const TTCN_Typedescriptor_t& p_td,
423 const ASN_BER_TLV_t& p_tlv,
424 unsigned L_form)
425{
426 bound_flag = FALSE;
427 BER_chk_descr(p_td);
428 ASN_BER_TLV_t stripped_tlv;
429 BER_decode_strip_tags(*p_td.ber, p_tlv, L_form, stripped_tlv);
430 TTCN_EncDec_ErrorContext ec("While decoding REAL type: ");
431 stripped_tlv.chk_constructed_flag(FALSE);
432 if (!stripped_tlv.isComplete) return FALSE;
433 size_t Vlen=stripped_tlv.V.str.Vlen;
434 unsigned char *Vstr=stripped_tlv.V.str.Vstr;
435 if(Vlen==0) {
436 float_value=0.0;
437 }
438 else if(Vstr[0] & 0x80) {
439 /* binary encoding */
440 /** \todo Perhaps it were good to implement this. Perhaps not. :) */
441 ec.warning("Sorry, decoding of binary encoded REAL values not"
442 " supported.");
443 float_value=0.0;
444 }
445 else if(Vstr[0] & 0x40) {
446 /* SpecialRealValue */
447 if(Vlen>1)
448 ec.error(TTCN_EncDec::ET_INVAL_MSG,
449 "In case of SpecialRealValue, the length of V-part must be 1"
450 " (See X.690 8.5.8).");
451 if(Vstr[0] & 0x3E)
452 ec.error(TTCN_EncDec::ET_INVAL_MSG,
453 "This is a reserved value: 0x%x (See X.690 8.5.8).",
454 Vstr[0]);
455 if(Vstr[0] & 0x01)
456 /* MINUS-INFINITY */
457 float_value=-INFINITY;
458 else
459 /* PLUS-INFINITY */
460 float_value=INFINITY;
461 }
462 else {
463 /* decimal encoding */
464 if((Vstr[0] & 0x3C) || (Vstr[0] & 0x3F) == 0x00 )
465 ec.error(TTCN_EncDec::ET_INVAL_MSG,
466 "This is a reserved value: 0x%x (See X.690 8.5.7).",
467 Vstr[0]);
468 int NR=Vstr[0] & 0x03; // which NumericalRepresentation
469 boolean
470 leadingzero=FALSE,
471 NR_error=FALSE;
472 unsigned char
473 *Vstr_last=Vstr+Vlen-1,
474 *sign=NULL,
475 *mant1=NULL,
476 *decmark=NULL,
477 *mant2=NULL,
478 *expmark=NULL,
479 *expsign=NULL,
480 *expo=NULL,
481 *ptr=Vstr+1;
482 size_t
483 mant1_len=0,
484 mant2_len=0,
485 expo_len=0;
486 long exponum;
487 if(Vlen==1) goto dec_error;
488 while(*ptr==' ') {
489 if(ptr==Vstr_last) goto dec_error;
490 ptr++;
491 }
492 if(*ptr=='+' || *ptr=='-') {
493 sign=ptr;
494 if(ptr==Vstr_last) goto dec_error;
495 ptr++;
496 }
497 while(*ptr=='0') {
498 leadingzero=TRUE;
499 if(ptr==Vstr_last) goto str_end;
500 ptr++;
501 }
502 while(*ptr>='0' && *ptr<='9') {
503 if(mant1_len==0) mant1=ptr;
504 mant1_len++;
505 if(ptr==Vstr_last) goto str_end;
506 ptr++;
507 }
508 if(*ptr=='.' || *ptr==',') {
509 decmark=ptr;
510 if(ptr==Vstr_last) goto str_end;
511 ptr++;
512 }
513 while(*ptr>='0' && *ptr<='9') {
514 if(mant2_len==0) mant2=ptr;
515 mant2_len++;
516 if(ptr==Vstr_last) goto str_end;
517 ptr++;
518 }
519 if(!leadingzero && !mant1 && !mant2) goto dec_error;
520 if(*ptr=='e' || *ptr=='E') {
521 expmark=ptr;
522 if(ptr==Vstr_last) goto dec_error;
523 ptr++;
524 }
525 if(*ptr=='+' || *ptr=='-') {
526 expsign=ptr;
527 if(ptr==Vstr_last) goto dec_error;
528 ptr++;
529 }
530 while(*ptr=='0') {
531 expo=ptr;
532 if(ptr==Vstr_last) goto str_end;
533 ptr++;
534 }
535 while(*ptr>='0' && *ptr<='9') {
536 if(expo_len==0) expo=ptr;
537 expo_len++;
538 if(ptr==Vstr_last) goto str_end;
539 ptr++;
540 }
541 if(expo_len==0 && expo!=NULL) expo_len=1; /* only leading zero */
542 if(expsign && !expo) goto dec_error;
543 ec.error(TTCN_EncDec::ET_INVAL_MSG,
544 "Superfluous part at the end of decimal encoding.");
545 str_end:
546 /* check NR */
547 if(NR==1) {
548 if(decmark || expmark) NR_error=TRUE;
549 }
550 else if(NR==2) {
551 if(expmark) NR_error=TRUE;
552 }
553 if(NR_error)
554 ec.error(TTCN_EncDec::ET_INVAL_MSG,
555 "This decimal encoding does not conform to NR%d form.", NR);
556 while(mant2_len>1 && mant2[mant2_len-1]=='0') mant2_len--;
557 if(mant2_len==1 && *mant2=='0') mant2_len=0, mant2=NULL;
558 float_value=0.0;
559 if(mant1) for(size_t i=0; i<mant1_len; i++) {
560 float_value*=10.0;
561 float_value+=static_cast<double>(mant1[i]-'0');
562 } // for i if...
563 if(mant2) for(size_t i=0; i<mant2_len; i++) {
564 float_value*=10.0;
565 float_value+=static_cast<double>(mant2[i]-'0');
566 } // for i if...
567 exponum=0;
568 if(expo) {
569 if(ceil(log10(log10(DBL_MAX)))<expo_len) {
570 /* overflow */
571 if(expsign && *expsign=='-') {
572 float_value=0.0;
573 }
574 else {
575 if(sign && *sign=='-') float_value=-INFINITY;
576 else float_value=INFINITY;
577 }
578 goto end;
579 } // overflow
580 else {
581 /* no overflow */
582 for(size_t i=0; i<expo_len; i++) {
583 exponum*=10;
584 exponum+=static_cast<int>(expo[i]-'0');
585 } // for i
586 if(expsign && *expsign=='-')
587 exponum*=-1;
588 } // no overflow
589 } // if expo
590 if(mant2) exponum-=mant2_len;
591 float_value*=pow(10.0, static_cast<double>(exponum));
592 goto end;
593 dec_error:
594 ec.error(TTCN_EncDec::ET_INVAL_MSG, "Erroneous decimal encoding.");
595 float_value=0.0;
596 }
597 end:
598 bound_flag=TRUE;
599 return TRUE;
600}
601
602int FLOAT::RAW_encode(const TTCN_Typedescriptor_t& p_td, RAW_enc_tree& myleaf) const
603{
604 unsigned char *bc;
605 unsigned char *dv;
606 int length = p_td.raw->fieldlength / 8;
607 double tmp = float_value;
608 if (!is_bound()) {
609 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,
610 "Encoding an unbound value.");
611 tmp = 0.0;
612 }
613 if (isnan(tmp)) {
614 TTCN_EncDec_ErrorContext::error_internal("Value is NaN.");
615 }
616 if (myleaf.must_free) Free(myleaf.body.leaf.data_ptr);
617 if (length > RAW_INT_ENC_LENGTH) {
618 myleaf.body.leaf.data_ptr = bc = (unsigned char*)Malloc(length*sizeof(*bc));
619 myleaf.must_free = TRUE;
620 myleaf.data_ptr_used = TRUE;
621 }
622 else {
623 bc = myleaf.body.leaf.data_array;
624 }
625 if (length == 8) {
626 dv = (unsigned char *) &tmp;
627#if defined __sparc__ || defined __sparc
628 memcpy(bc,dv,8);
629#else
630 for (int i = 0, k = 7; i < 8; i++, k--) bc[i] = dv[k];
631#endif
632 }
633 else if (length == 4) {
634 if (tmp == 0.0) memset(bc, 0, 4);
635 else if (tmp == -0.0) {
636 memset(bc, 0, 4);
637 bc[0] |= 0x80;
638 }
639 else {
640#if defined __sparc__ || defined __sparc
641 int index=0;
642 int adj=1;
643#else
644 int index = 7;
645 int adj = -1;
646#endif
647 dv = (unsigned char *) &tmp;
648 bc[0] = dv[index] & 0x80;
649 int exponent = dv[index] & 0x7F;
650 exponent <<= 4;
651 index += adj;
652 exponent += (dv[index] & 0xF0) >> 4;
653 exponent -= 1023;
654
655 if (exponent > 127) {
656 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR,
657 "The float value '%f' is out of the range of "
658 "the single precision: %s", (double)float_value, p_td.name);
659 tmp = 0.0;
660 exponent = 0;
661 }
662 else if (exponent < -127) {
663 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_FLOAT_TR,
664 "The float value '%f' is too small to represent it "
665 "in single precision: %s", (double)float_value, p_td.name);
666 tmp = 0.0;
667 exponent = 0;
668 }
669 else exponent += 127;
670 bc[0] |= (exponent >> 1) & 0x7F;
671 bc[1] = ((exponent << 7) & 0x80) | ((dv[index] & 0x0F) << 3)
672 | ((dv[index + adj] & 0xE0) >> 5);
673 index += adj;
674 bc[2] = ((dv[index] & 0x1F) << 3) | ((dv[index + adj] & 0xE0) >> 5);
675 index += adj;
676 bc[3] = ((dv[index] & 0x1F) << 3) | ((dv[index + adj] & 0xE0) >> 5);
677 }
678 }
679 else
680 TTCN_EncDec_ErrorContext::error_internal("Invalid FLOAT length %d", length);
681
682 return myleaf.length = p_td.raw->fieldlength;
683}
684
685int FLOAT::RAW_decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& buff,
686 int limit, raw_order_t top_bit_ord, boolean no_err, int /*sel_field*/,
687 boolean /*first_call*/)
688{
689 int prepaddlength = buff.increase_pos_padd(p_td.raw->prepadding);
690 unsigned char *dv;
691 limit -= prepaddlength;
692 int decode_length = p_td.raw->fieldlength;
693 if ( p_td.raw->fieldlength > limit
694 || p_td.raw->fieldlength > (int) buff.unread_len_bit()) {
695 if (no_err) return -1;
696 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR,
697 "There is not enough bits in the buffer to decode type %s.", p_td.name);
698 decode_length = limit > (int) buff.unread_len_bit()
699 ? buff.unread_len_bit() : limit;
700 bound_flag = TRUE;
701 float_value = 0.0;
702 decode_length += buff.increase_pos_padd(p_td.raw->padding);
703 return decode_length + prepaddlength;
704 }
705 double tmp = 0.0;
706 unsigned char data[16];
707 RAW_coding_par cp;
708 boolean orders = FALSE;
709 if (p_td.raw->bitorderinoctet == ORDER_MSB) orders = TRUE;
710 if (p_td.raw->bitorderinfield == ORDER_MSB) orders = !orders;
711 cp.bitorder = orders ? ORDER_MSB : ORDER_LSB;
712 orders = FALSE;
713 if (p_td.raw->byteorder == ORDER_MSB) orders = TRUE;
714 if (p_td.raw->bitorderinfield == ORDER_MSB) orders = !orders;
715 cp.byteorder = orders ? ORDER_MSB : ORDER_LSB;
716 cp.fieldorder = p_td.raw->fieldorder;
717 cp.hexorder = ORDER_LSB;
718 buff.get_b((size_t) decode_length, data, cp, top_bit_ord);
719 if (decode_length == 64) {
720 dv = (unsigned char *) &tmp;
721#if defined __sparc__ || defined __sparc
722 memcpy(dv,data,8);
723#else
724 for (int i = 0, k = 7; i < 8; i++, k--) dv[i] = data[k];
725#endif
726 if (isnan(tmp)) {
727 if (no_err) return -1;
728 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR,
729 "Not a Number received for type %s.", p_td.name);
730 tmp = 0.0;
731 }
732 }
733 else if (decode_length == 32) {
734 int sign = (data[0] & 0x80) >> 7;
735 int exponent = ((data[0] & 0x7F) << 1) | ((data[1] & 0x80) >> 7);
736 int fraction = ((data[1] & 0x7F) << 1) | ((data[2] & 0x80) >> 7);
737 fraction <<= 8;
738 fraction += ((data[2] & 0x7F) << 1) | ((data[3] & 0x80) >> 7);
739 fraction <<= 7;
740 fraction += data[3] & 0x7F;
741 if (exponent == 0 && fraction == 0) tmp = sign ? -0.0 : 0.0;
742 else if (exponent == 0xFF && fraction != 0) {
743 if (no_err) return -1;
744 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR,
745 "Not a Number received for type %s.", p_td.name);
746 tmp = 0.0;
747 }
748 else if (exponent == 0 && fraction != 0) {
749 double sign_v = sign ? -1.0 : 1.0;
750 tmp = sign_v * (static_cast<double> (fraction) / 8388608.0)
751 * pow(2.0, -126.0);
752 }
753 else {
754 double sign_v = sign ? -1.0 : 1.0;
755 exponent -= 127;
756 tmp = sign_v * (1.0 + static_cast<double> (fraction) / 8388608.0)
757 * pow(2.0, static_cast<double> (exponent));
758 }
759
760 }
761 decode_length += buff.increase_pos_padd(p_td.raw->padding);
762 bound_flag = TRUE;
763 float_value = tmp;
764 return decode_length + prepaddlength;
765}
766
767int FLOAT::XER_encode(const XERdescriptor_t& p_td,
af710487 768 TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const
970ed795
EL
769{
770 if(!is_bound()) {
771 TTCN_EncDec_ErrorContext::error(
772 TTCN_EncDec::ET_UNBOUND, "Encoding an unbound float value.");
773 }
774 int exer = is_exer(flavor |= SIMPLE_TYPE);
775 // SIMPLE_TYPE has no influence on is_exer, we set it for later
776 int encoded_length=(int)p_buf.get_len();
777 flavor &= ~XER_RECOF; // float doesn't care
778
779 begin_xml(p_td, p_buf, flavor, indent, false);
780
781 if (exer && (p_td.xer_bits & XER_DECIMAL)) {
782 char buf[312];
783 int n = snprintf(buf, sizeof(buf), "%f", (double)float_value);
784 p_buf.put_s((size_t)n, (const unsigned char*)buf);
785 }
786 else {
787 CHARSTRING value = float2str(float_value);
788 p_buf.put_string(value);
789 }
790
791 end_xml(p_td, p_buf, flavor, indent, false);
792
793 return (int)p_buf.get_len() - encoded_length;
794}
795
a38c6d4c 796boolean FLOAT::is_float(const char* p_str)
797{
798 bool first_digit = false; // first digit reached
799 bool decimal_point = false; // decimal point (.) reached
800 bool exponent_mark = false; // exponential mark (e or E) reached
801 bool exponent_sign = false; // sign of the exponential (- or +) reached
802
803 if ('-' == *p_str || '+' == *p_str) {
804 ++p_str;
805 }
806
807 while (0 != *p_str) {
808 switch(*p_str) {
809 case '.':
810 if (decimal_point || exponent_mark || !first_digit) {
811 return false;
812 }
813 decimal_point = true;
814 first_digit = false;
815 break;
816 case 'e':
817 case 'E':
818 if (exponent_mark || !first_digit) {
819 return false;
820 }
821 exponent_mark = true;
822 first_digit = false;
823 break;
824 case '0':
825 case '1':
826 case '2':
827 case '3':
828 case '4':
829 case '5':
830 case '6':
831 case '7':
832 case '8':
833 case '9':
834 first_digit = true;
835 break;
836 case '-':
837 case '+':
838 if (exponent_sign || !exponent_mark || first_digit) {
839 return false;
840 }
841 exponent_sign = true;
842 break;
843 default:
844 return false;
845 }
846
847 ++p_str;
848 }
849 return first_digit;
850}
851
970ed795 852int FLOAT::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader,
af710487 853 unsigned int flavor, embed_values_dec_struct_t*)
970ed795 854{
a38c6d4c 855 bound_flag = false;
970ed795
EL
856 int exer = is_exer(flavor);
857 int success = reader.Ok(), depth = -1;
858 if (success <= 0) return 0;
859 boolean own_tag = !(exer && (p_td.xer_bits & UNTAGGED)) && !is_exerlist(flavor);
860
861 if (!own_tag) goto tagless;
862 if (exer && (p_td.xer_bits & XER_ATTRIBUTE)) {
863 verify_name(reader, p_td, exer);
864tagless:
865 const char * value = (const char *)reader.Value();
866
a38c6d4c 867 if (value && is_float(value)) {
970ed795 868 bound_flag = true;
a38c6d4c 869 sscanf(value, "%lf", &float_value);
870 }
970ed795
EL
871
872 // Let the caller do reader.AdvanceAttribute();
873 }
874 else {
875 for (; success == 1; success = reader.Read()) {
876 int type = reader.NodeType();
877 if (XML_READER_TYPE_ELEMENT == type) {
878 verify_name(reader, p_td, exer);
879 if (reader.IsEmptyElement()) {
880 if (exer && p_td.dfeValue != 0) {
881 *this = *static_cast<const FLOAT*>(p_td.dfeValue);
882 }
883 reader.Read();
884 break;
885 }
886 depth = reader.Depth();
887 }
888 else if (XML_READER_TYPE_TEXT == type && depth != -1) {
889 const char * value = (const char*)reader.Value();
a38c6d4c 890 if (value && is_float(value)) {
970ed795 891 bound_flag = true;
a38c6d4c 892 sscanf(value, "%lf", &float_value);
893 }
970ed795
EL
894 }
895 else if (XML_READER_TYPE_END_ELEMENT == type) {
896 verify_end(reader, p_td, depth, exer);
897 if (!bound_flag && exer && p_td.dfeValue != 0) {
898 *this = *static_cast<const FLOAT*>(p_td.dfeValue);
899 }
900 reader.Read();
901 break;
902 }
903 } // next read
904 } // if not attribute
905 return 1; // decode successful
906}
907
908const char* POS_INF_STR = "\"infinity\"";
909const char* NEG_INF_STR = "\"-infinity\"";
910const char* NAN_STR = "\"not_a_number\"";
911
912int FLOAT::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) const
913{
914 if (!is_bound()) {
915 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,
916 "Encoding an unbound float value.");
917 return -1;
918 }
919
920 double value = (double)float_value;
921 if ((double)INFINITY == value) {
922 return p_tok.put_next_token(JSON_TOKEN_STRING, POS_INF_STR);
923 }
924 if (-(double)INFINITY == value) {
925 return p_tok.put_next_token(JSON_TOKEN_STRING, NEG_INF_STR);
926 }
927 if (isnan(value)) {
928 return p_tok.put_next_token(JSON_TOKEN_STRING, NAN_STR);
929 }
930
931 // true if decimal representation possible (use %f format)
932 bool decimal_repr = (value == 0.0)
933 || (value > -MAX_DECIMAL_FLOAT && value <= -MIN_DECIMAL_FLOAT)
934 || (value >= MIN_DECIMAL_FLOAT && value < MAX_DECIMAL_FLOAT);
935
936 char* tmp_str = mprintf(decimal_repr ? "%f" : "%e", value);
937 int enc_len = p_tok.put_next_token(JSON_TOKEN_NUMBER, tmp_str);
938 Free(tmp_str);
939 return enc_len;
940}
941
942int FLOAT::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent)
943{
944 bound_flag = false;
945 json_token_t token = JSON_TOKEN_NONE;
946 char* value = 0;
947 size_t value_len = 0;
948 int dec_len = 0;
949 boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();
950 if (use_default) {
951 // No JSON data in the buffer -> use default value
952 value = (char*)p_td.json->default_value;
953 value_len = strlen(value);
954 } else {
955 dec_len = p_tok.get_next_token(&token, &value, &value_len);
956 }
957 if (JSON_TOKEN_ERROR == token) {
958 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, "");
959 return JSON_ERROR_FATAL;
960 }
961 else if (JSON_TOKEN_STRING == token || use_default) {
962 if (0 == strncmp(value, POS_INF_STR + (use_default ? 1 : 0), value_len)) {
963 bound_flag = true;
964 float_value = INFINITY;
965 }
966 else if (0 == strncmp(value, NEG_INF_STR + (use_default ? 1 : 0), value_len)) {
967 bound_flag = true;
968 float_value = -INFINITY;
969 }
970 else if (0 == strncmp(value, NAN_STR + (use_default ? 1 : 0), value_len)) {
971 bound_flag = true;
972#ifdef NAN
973 float_value = NAN;
974#else
975 float_value = INFINITY + (-INFINITY);
976#endif
977 }
978 else if (!use_default) {
979 char* spec_val = mprintf("float (%s, %s or %s)", POS_INF_STR, NEG_INF_STR, NAN_STR);
980 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_FORMAT_ERROR, "string", spec_val);
981 Free(spec_val);
982 bound_flag = false;
983 return JSON_ERROR_FATAL;
984 }
985 }
986 else if (JSON_TOKEN_NUMBER == token) {
987 char* value2 = mcopystrn(value, value_len);
988 sscanf(value2, "%lf", &float_value);
989 bound_flag = true;
990 Free(value2);
991 } else {
992 return JSON_ERROR_INVALID_TOKEN;
993 }
994 if (!bound_flag && use_default) {
995 // Already checked the default value for the string possibilities, now
996 // check for a valid number
997 char* value2 = mcopystrn(value, value_len);
998 sscanf(value2, "%lf", &float_value);
999 bound_flag = true;
1000 Free(value2);
1001 }
1002 return dec_len;
1003}
1004
1005
1006// global functions
1007
1008double operator+(double double_value, const FLOAT& other_value)
1009{
1010 other_value.must_bound("Unbound right operand of float addition.");
1011 FLOAT::check_numeric(double_value, "Left operand of float addition");
1012 FLOAT::check_numeric(other_value.float_value, "Right operand of float addition");
1013 return double_value + other_value.float_value;
1014}
1015
1016double operator-(double double_value, const FLOAT& other_value)
1017{
1018 other_value.must_bound("Unbound right operand of float subtraction.");
1019 FLOAT::check_numeric(double_value, "Left operand of float subtraction");
1020 FLOAT::check_numeric(other_value.float_value, "Right operand of float subtraction");
1021 return double_value - other_value.float_value;
1022}
1023
1024double operator*(double double_value, const FLOAT& other_value)
1025{
1026 other_value.must_bound("Unbound right operand of float multiplication.");
1027 FLOAT::check_numeric(double_value, "Left operand of float multiplication");
1028 FLOAT::check_numeric(other_value.float_value, "Right operand of float multiplication");
1029 return double_value * other_value.float_value;
1030}
1031
1032double operator/(double double_value, const FLOAT& other_value)
1033{
1034 other_value.must_bound("Unbound right operand of float division.");
1035 FLOAT::check_numeric(double_value, "Left operand of float division");
1036 FLOAT::check_numeric(other_value.float_value, "Right operand of float division");
1037 if (other_value.float_value == 0.0) TTCN_error("Float division by zero.");
1038 return double_value / other_value.float_value;
1039}
1040
1041boolean operator==(double double_value, const FLOAT& other_value)
1042{
1043 other_value.must_bound("Unbound right operand of float comparison.");
1044 return double_value == other_value.float_value;
1045}
1046
1047boolean operator<(double double_value, const FLOAT& other_value)
1048{
1049 other_value.must_bound("Unbound right operand of float comparison.");
1050 return double_value < other_value.float_value;
1051}
1052
1053boolean operator>(double double_value, const FLOAT& other_value)
1054{
1055 other_value.must_bound("Unbound right operand of float comparison.");
1056 return double_value > other_value.float_value;
1057}
1058
1059// float template class
1060
1061void FLOAT_template::clean_up()
1062{
1063 if (template_selection == VALUE_LIST ||
1064 template_selection == COMPLEMENTED_LIST)
1065 delete [] value_list.list_value;
1066 template_selection = UNINITIALIZED_TEMPLATE;
1067}
1068
1069void FLOAT_template::copy_template(const FLOAT_template& other_value)
1070{
1071 switch (other_value.template_selection) {
1072 case SPECIFIC_VALUE:
1073 single_value = other_value.single_value;
1074 break;
1075 case OMIT_VALUE:
1076 case ANY_VALUE:
1077 case ANY_OR_OMIT:
1078 break;
1079 case VALUE_LIST:
1080 case COMPLEMENTED_LIST:
1081 value_list.n_values = other_value.value_list.n_values;
1082 value_list.list_value = new FLOAT_template[value_list.n_values];
1083 for (unsigned int i = 0; i < value_list.n_values; i++)
1084 value_list.list_value[i].copy_template(
1085 other_value.value_list.list_value[i]);
1086 break;
1087 case VALUE_RANGE:
1088 value_range = other_value.value_range;
1089 break;
1090 default:
1091 TTCN_error("Copying an uninitialized/unsupported float template.");
1092 }
1093 set_selection(other_value);
1094}
1095
1096FLOAT_template::FLOAT_template()
1097{
1098
1099}
1100
1101FLOAT_template::FLOAT_template(template_sel other_value)
1102 : Base_Template(other_value)
1103{
1104 check_single_selection(other_value);
1105}
1106
1107FLOAT_template::FLOAT_template(double other_value)
1108 : Base_Template(SPECIFIC_VALUE)
1109{
1110 single_value = other_value;
1111}
1112
1113FLOAT_template::FLOAT_template(const FLOAT& other_value)
1114 : Base_Template(SPECIFIC_VALUE)
1115{
1116 other_value.must_bound("Creating a template from an unbound float value.");
1117 single_value = other_value.float_value;
1118}
1119
1120FLOAT_template::FLOAT_template(const OPTIONAL<FLOAT>& other_value)
1121{
1122 switch (other_value.get_selection()) {
1123 case OPTIONAL_PRESENT:
1124 set_selection(SPECIFIC_VALUE);
1125 single_value = (double)(const FLOAT&)other_value;
1126 break;
1127 case OPTIONAL_OMIT:
1128 set_selection(OMIT_VALUE);
1129 break;
1130 default:
1131 TTCN_error("Creating a float template from an unbound optional field.");
1132 }
1133}
1134
1135FLOAT_template::FLOAT_template(const FLOAT_template& other_value)
1136: Base_Template()
1137{
1138 copy_template(other_value);
1139}
1140
1141FLOAT_template::~FLOAT_template()
1142{
1143 clean_up();
1144}
1145
1146FLOAT_template& FLOAT_template::operator=(template_sel other_value)
1147{
1148 check_single_selection(other_value);
1149 clean_up();
1150 set_selection(other_value);
1151 return *this;
1152}
1153
1154FLOAT_template& FLOAT_template::operator=(double other_value)
1155{
1156 clean_up();
1157 set_selection(SPECIFIC_VALUE);
1158 single_value = other_value;
1159 return *this;
1160}
1161
1162FLOAT_template& FLOAT_template::operator=(const FLOAT& other_value)
1163{
1164 other_value.must_bound("Assignment of an unbound float value "
1165 "to a template.");
1166 clean_up();
1167 set_selection(SPECIFIC_VALUE);
1168 single_value = other_value.float_value;
1169 return *this;
1170}
1171
1172FLOAT_template& FLOAT_template::operator=(const OPTIONAL<FLOAT>& other_value)
1173{
1174 clean_up();
1175 switch (other_value.get_selection()) {
1176 case OPTIONAL_PRESENT:
1177 set_selection(SPECIFIC_VALUE);
1178 single_value = (double)(const FLOAT&)other_value;
1179 break;
1180 case OPTIONAL_OMIT:
1181 set_selection(OMIT_VALUE);
1182 break;
1183 default:
1184 TTCN_error("Assignment of an unbound optional field to a float template.");
1185 }
1186 return *this;
1187}
1188
1189FLOAT_template& FLOAT_template::operator=(const FLOAT_template& other_value)
1190{
1191 if (&other_value != this) {
1192 clean_up();
1193 copy_template(other_value);
1194 }
1195 return *this;
1196}
1197
1198boolean FLOAT_template::match(double other_value) const
1199{
1200 switch (template_selection) {
1201 case SPECIFIC_VALUE:
1202 return single_value == other_value;
1203 case OMIT_VALUE:
1204 return FALSE;
1205 case ANY_VALUE:
1206 case ANY_OR_OMIT:
1207 return TRUE;
1208 case VALUE_LIST:
1209 case COMPLEMENTED_LIST:
1210 for (unsigned int i = 0; i < value_list.n_values; i++)
1211 if(value_list.list_value[i].match(other_value))
1212 return template_selection == VALUE_LIST;
1213 return template_selection == COMPLEMENTED_LIST;
1214 case VALUE_RANGE:
1215 return (!value_range.min_is_present ||
1216 value_range.min_value <= other_value) &&
1217 (!value_range.max_is_present ||
1218 value_range.max_value >= other_value);
1219 default:
1220 TTCN_error("Matching with an uninitialized/unsupported float template.");
1221 }
1222 return FALSE;
1223}
1224
1225boolean FLOAT_template::match(const FLOAT& other_value) const
1226{
1227 if (!other_value.is_bound()) return FALSE;
1228 return match(other_value.float_value);
1229}
1230
1231
1232void FLOAT_template::set_type(template_sel template_type,
1233 unsigned int list_length)
1234{
1235 clean_up();
1236 switch (template_type) {
1237 case VALUE_LIST:
1238 case COMPLEMENTED_LIST:
1239 set_selection(template_type);
1240 value_list.n_values = list_length;
1241 value_list.list_value = new FLOAT_template[list_length];
1242 break;
1243 case VALUE_RANGE:
1244 set_selection(VALUE_RANGE);
1245 value_range.min_is_present = FALSE;
1246 value_range.max_is_present = FALSE;
1247 break;
1248 default:
1249 TTCN_error("Setting an invalid type for a float template.");
1250 }
1251}
1252
1253FLOAT_template& FLOAT_template::list_item(unsigned int list_index)
1254{
1255 if (template_selection != VALUE_LIST &&
1256 template_selection != COMPLEMENTED_LIST)
1257 TTCN_error("Accessing a list element of a non-list float template.");
1258 if (list_index >= value_list.n_values)
1259 TTCN_error("Index overflow in a float value list template.");
1260 return value_list.list_value[list_index];
1261}
1262
1263void FLOAT_template::set_min(double min_value)
1264{
1265 if (template_selection != VALUE_RANGE)
1266 TTCN_error("Float template is not range when setting lower limit.");
1267 if (value_range.max_is_present && value_range.max_value < min_value)
1268 TTCN_error("The lower limit of the range is greater than the "
1269 "upper limit in a float template.");
1270 value_range.min_is_present = TRUE;
1271 value_range.min_value = min_value;
1272}
1273
1274void FLOAT_template::set_min(const FLOAT& min_value)
1275{
1276 min_value.must_bound("Using an unbound value when setting the lower bound "
1277 "in a float range template.");
1278 set_min(min_value.float_value);
1279}
1280
1281void FLOAT_template::set_max(double max_value)
1282{
1283 if (template_selection != VALUE_RANGE)
1284 TTCN_error("Float template is not range when setting upper limit.");
1285 if (value_range.min_is_present && value_range.min_value > max_value)
1286 TTCN_error("The upper limit of the range is smaller than the "
1287 "lower limit in a float template.");
1288 value_range.max_is_present = TRUE;
1289 value_range.max_value = max_value;
1290}
1291
1292void FLOAT_template::set_max(const FLOAT& max_value)
1293{
1294 max_value.must_bound("Using an unbound value when setting the upper bound "
1295 "in a float range template.");
1296 set_max(max_value.float_value);
1297}
1298
1299double FLOAT_template::valueof() const
1300{
1301 if (template_selection != SPECIFIC_VALUE || is_ifpresent)
1302 TTCN_error("Performing a valueof "
1303 "or send operation on a non-specific float template.");
1304 return single_value;
1305}
1306
1307void FLOAT_template::log() const
1308{
1309 switch (template_selection) {
1310 case SPECIFIC_VALUE:
1311 log_float(single_value);
1312 break;
1313 case COMPLEMENTED_LIST:
1314 TTCN_Logger::log_event_str("complement ");
1315 // no break
1316 case VALUE_LIST:
1317 TTCN_Logger::log_char('(');
1318 for (unsigned int i = 0; i < value_list.n_values; i++) {
1319 if (i > 0) TTCN_Logger::log_event_str(", ");
1320 value_list.list_value[i].log();
1321 }
1322 TTCN_Logger::log_char(')');
1323 break;
1324 case VALUE_RANGE:
1325 TTCN_Logger::log_char('(');
1326 if (value_range.min_is_present) log_float(value_range.min_value);
1327 else TTCN_Logger::log_event_str("-infinity");
1328 TTCN_Logger::log_event_str(" .. ");
1329 if (value_range.max_is_present) log_float(value_range.max_value);
1330 else TTCN_Logger::log_event_str("infinity");
1331 TTCN_Logger::log_char(')');
1332 break;
1333 default:
1334 log_generic();
1335 break;
1336 }
1337 log_ifpresent();
1338}
1339
1340void FLOAT_template::log_match(const FLOAT& match_value) const
1341{
1342 if (TTCN_Logger::VERBOSITY_COMPACT == TTCN_Logger::get_matching_verbosity()
1343 && TTCN_Logger::get_logmatch_buffer_len() != 0) {
1344 TTCN_Logger::print_logmatch_buffer();
1345 TTCN_Logger::log_event_str(" := ");
1346 }
1347 match_value.log();
1348 TTCN_Logger::log_event_str(" with ");
1349 log();
1350 if (match(match_value)) TTCN_Logger::log_event_str(" matched");
1351 else TTCN_Logger::log_event_str(" unmatched");
1352}
1353
1354void FLOAT_template::set_param(Module_Param& param) {
1355 param.basic_check(Module_Param::BC_TEMPLATE, "float template");
1356 switch (param.get_type()) {
1357 case Module_Param::MP_Omit:
1358 *this = OMIT_VALUE;
1359 break;
1360 case Module_Param::MP_Any:
1361 *this = ANY_VALUE;
1362 break;
1363 case Module_Param::MP_AnyOrNone:
1364 *this = ANY_OR_OMIT;
1365 break;
1366 case Module_Param::MP_List_Template:
1367 case Module_Param::MP_ComplementList_Template:
1368 set_type(param.get_type()==Module_Param::MP_List_Template ? VALUE_LIST : COMPLEMENTED_LIST, param.get_size());
1369 for (size_t i=0; i<param.get_size(); i++) {
1370 list_item(i).set_param(*param.get_elem(i));
1371 }
1372 break;
1373 case Module_Param::MP_Float:
1374 *this = param.get_float();
1375 break;
1376 case Module_Param::MP_FloatRange:
1377 set_type(VALUE_RANGE);
1378 if (param.has_lower_float()) set_min(param.get_lower_float());
1379 if (param.has_upper_float()) set_max(param.get_upper_float());
1380 break;
1381 default:
1382 param.type_error("float template");
1383 }
1384 is_ifpresent = param.get_ifpresent();
1385}
1386
1387void FLOAT_template::encode_text(Text_Buf& text_buf) const
1388{
1389 encode_text_base(text_buf);
1390 switch (template_selection) {
1391 case OMIT_VALUE:
1392 case ANY_VALUE:
1393 case ANY_OR_OMIT:
1394 break;
1395 case SPECIFIC_VALUE:
1396 text_buf.push_double(single_value);
1397 break;
1398 case VALUE_LIST:
1399 case COMPLEMENTED_LIST:
1400 text_buf.push_int(value_list.n_values);
1401 for (unsigned int i = 0; i < value_list.n_values; i++)
1402 value_list.list_value[i].encode_text(text_buf);
1403 break;
1404 case VALUE_RANGE:
1405 text_buf.push_int(value_range.min_is_present ? 1 : 0);
1406 if (value_range.min_is_present)
1407 text_buf.push_double(value_range.min_value);
1408 text_buf.push_int(value_range.max_is_present ? 1 : 0);
1409 if (value_range.max_is_present)
1410 text_buf.push_double(value_range.max_value);
1411 break;
1412 default:
1413 TTCN_error("Text encoder: Encoding an undefined/unsupported "
1414 "float template.");
1415 }
1416}
1417
1418void FLOAT_template::decode_text(Text_Buf& text_buf)
1419{
1420 clean_up();
1421 decode_text_base(text_buf);
1422 switch (template_selection) {
1423 case OMIT_VALUE:
1424 case ANY_VALUE:
1425 case ANY_OR_OMIT:
1426 break;
1427 case SPECIFIC_VALUE:
1428 single_value = text_buf.pull_double();
1429 break;
1430 case VALUE_LIST:
1431 case COMPLEMENTED_LIST:
1432 value_list.n_values = text_buf.pull_int().get_val();
1433 value_list.list_value = new FLOAT_template[value_list.n_values];
1434 for (unsigned int i = 0; i < value_list.n_values; i++)
1435 value_list.list_value[i].decode_text(text_buf);
1436 break;
1437 case VALUE_RANGE:
1438 value_range.min_is_present = text_buf.pull_int() != 0;
1439 if (value_range.min_is_present)
1440 value_range.min_value = text_buf.pull_double();
1441 value_range.max_is_present = text_buf.pull_int() != 0;
1442 if (value_range.max_is_present)
1443 value_range.max_value = text_buf.pull_double();
1444 break;
1445 default:
1446 TTCN_error("Text decoder: An unknown/unsupported selection was "
1447 "received for a float template.");
1448 }
1449}
1450
1451boolean FLOAT_template::is_present() const
1452{
1453 if (template_selection==UNINITIALIZED_TEMPLATE) return FALSE;
1454 return !match_omit();
1455}
1456
1457boolean FLOAT_template::match_omit() const
1458{
1459 if (is_ifpresent) return TRUE;
1460 switch (template_selection) {
1461 case OMIT_VALUE:
1462 case ANY_OR_OMIT:
1463 return TRUE;
1464 case VALUE_LIST:
1465 case COMPLEMENTED_LIST:
1466 for (unsigned int i=0; i<value_list.n_values; i++)
1467 if (value_list.list_value[i].match_omit())
1468 return template_selection==VALUE_LIST;
1469 return template_selection==COMPLEMENTED_LIST;
1470 default:
1471 return FALSE;
1472 }
1473 return FALSE;
1474}
1475
1476#ifndef TITAN_RUNTIME_2
1477void FLOAT_template::check_restriction(template_res t_res, const char* t_name) const
1478{
1479 if (template_selection==UNINITIALIZED_TEMPLATE) return;
1480 switch ((t_name&&(t_res==TR_VALUE))?TR_OMIT:t_res) {
1481 case TR_VALUE:
1482 if (!is_ifpresent && template_selection==SPECIFIC_VALUE) return;
1483 break;
1484 case TR_OMIT:
1485 if (!is_ifpresent && (template_selection==OMIT_VALUE ||
1486 template_selection==SPECIFIC_VALUE)) return;
1487 break;
1488 case TR_PRESENT:
1489 if (!match_omit()) return;
1490 break;
1491 default:
1492 return;
1493 }
1494 TTCN_error("Restriction `%s' on template of type %s violated.",
1495 get_res_name(t_res), t_name ? t_name : "float");
1496}
1497#endif
This page took 0.077814 seconds and 5 git commands to generate.