Sync with 5.4.3
[deliverable/titan.core.git] / core / Float.cc
CommitLineData
970ed795 1///////////////////////////////////////////////////////////////////////////////
3abe9331 2// Copyright (c) 2000-2015 Ericsson Telecom AB
970ed795
EL
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");
3abe9331 247 Module_Param_Ptr mp = &param;
248 if (param.get_type() == Module_Param::MP_Reference) {
249 mp = param.get_referenced_param();
250 }
251 switch (mp->get_type()) {
252 case Module_Param::MP_Float: {
253 clean_up();
254 bound_flag = TRUE;
255 float_value = mp->get_float();
256 break; }
257 case Module_Param::MP_Expression:
258 switch (mp->get_expr_type()) {
259 case Module_Param::EXPR_NEGATE: {
260 FLOAT operand;
261 operand.set_param(*mp->get_operand1());
262 *this = - operand;
263 break; }
264 case Module_Param::EXPR_ADD: {
265 FLOAT operand1, operand2;
266 operand1.set_param(*mp->get_operand1());
267 operand2.set_param(*mp->get_operand2());
268 *this = operand1 + operand2;
269 break; }
270 case Module_Param::EXPR_SUBTRACT: {
271 FLOAT operand1, operand2;
272 operand1.set_param(*mp->get_operand1());
273 operand2.set_param(*mp->get_operand2());
274 *this = operand1 - operand2;
275 break; }
276 case Module_Param::EXPR_MULTIPLY: {
277 FLOAT operand1, operand2;
278 operand1.set_param(*mp->get_operand1());
279 operand2.set_param(*mp->get_operand2());
280 *this = operand1 * operand2;
281 break; }
282 case Module_Param::EXPR_DIVIDE: {
283 FLOAT operand1, operand2;
284 operand1.set_param(*mp->get_operand1());
285 operand2.set_param(*mp->get_operand2());
286 if (operand2 == 0.0) {
287 param.error("Floating point division by zero.");
288 }
289 *this = operand1 / operand2;
290 break; }
291 default:
292 param.expr_type_error("a float");
293 break;
294 }
295 break;
296 default:
297 param.type_error("float value");
298 break;
299 }
300}
301
302Module_Param* FLOAT::get_param(Module_Param_Name& /* param_name */) const
303{
304 if (!bound_flag) {
305 return new Module_Param_Unbound();
306 }
307 return new Module_Param_Float(float_value);
970ed795
EL
308}
309
310void FLOAT::encode_text(Text_Buf& text_buf) const
311{
312 must_bound("Text encoder: Encoding an unbound float value.");
313 text_buf.push_double(float_value);
314}
315
316void FLOAT::decode_text(Text_Buf& text_buf)
317{
318 bound_flag = TRUE;
319 float_value = text_buf.pull_double();
320}
321
322void FLOAT::encode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
323 TTCN_EncDec::coding_t p_coding, ...) const
324{
325 va_list pvar;
326 va_start(pvar, p_coding);
327 switch(p_coding) {
328 case TTCN_EncDec::CT_BER: {
329 TTCN_EncDec_ErrorContext ec("While BER-encoding type '%s': ", p_td.name);
330 unsigned BER_coding=va_arg(pvar, unsigned);
331 BER_encode_chk_coding(BER_coding);
332 ASN_BER_TLV_t *tlv=BER_encode_TLV(p_td, BER_coding);
333 tlv->put_in_buffer(p_buf);
334 ASN_BER_TLV_t::destruct(tlv);
335 break;}
336 case TTCN_EncDec::CT_RAW: {
337 TTCN_EncDec_ErrorContext ec("While RAW-encoding type '%s': ", p_td.name);
338 if(!p_td.raw)
339 TTCN_EncDec_ErrorContext::error_internal
340 ("No RAW descriptor available for type '%s'.", p_td.name);
341 RAW_enc_tr_pos rp;
342 rp.level=0;
343 rp.pos=NULL;
344 RAW_enc_tree root(TRUE,NULL,&rp,1,p_td.raw);
345 RAW_encode(p_td, root);
346 root.put_to_buf(p_buf);
347 break;}
348 case TTCN_EncDec::CT_XER: {
349 TTCN_EncDec_ErrorContext ec("While XER-encoding type '%s': ", p_td.name);
350 unsigned XER_coding=va_arg(pvar, unsigned);
af710487 351 XER_encode(*p_td.xer, p_buf, XER_coding, 0, 0);
970ed795
EL
352 break;}
353 case TTCN_EncDec::CT_JSON: {
354 TTCN_EncDec_ErrorContext ec("While JSON-encoding type '%s': ", p_td.name);
355 if(!p_td.json)
356 TTCN_EncDec_ErrorContext::error_internal
357 ("No JSON descriptor available for type '%s'.", p_td.name);
358 JSON_Tokenizer tok(va_arg(pvar, int) != 0);
359 JSON_encode(p_td, tok);
360 p_buf.put_s(tok.get_buffer_length(), (const unsigned char*)tok.get_buffer());
361 break;}
362 default:
363 TTCN_error("Unknown coding method requested to encode type '%s'",
364 p_td.name);
365 }
366 va_end(pvar);
367}
368
369void FLOAT::decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& p_buf,
370 TTCN_EncDec::coding_t p_coding, ...)
371{
372 va_list pvar;
373 va_start(pvar, p_coding);
374 switch(p_coding) {
375 case TTCN_EncDec::CT_BER: {
376 TTCN_EncDec_ErrorContext ec("While BER-decoding type '%s': ", p_td.name);
377 unsigned L_form=va_arg(pvar, unsigned);
378 ASN_BER_TLV_t tlv;
379 BER_decode_str2TLV(p_buf, tlv, L_form);
380 BER_decode_TLV(p_td, tlv, L_form);
381 if(tlv.isComplete) p_buf.increase_pos(tlv.get_len());
382 break;}
383 case TTCN_EncDec::CT_RAW: {
384 TTCN_EncDec_ErrorContext ec("While RAW-decoding type '%s': ", p_td.name);
385 if(!p_td.raw)
386 TTCN_EncDec_ErrorContext::error_internal
387 ("No RAW descriptor available for type '%s'.", p_td.name);
388 raw_order_t order;
389 switch(p_td.raw->top_bit_order){
390 case TOP_BIT_LEFT:
391 order=ORDER_LSB;
392 break;
393 case TOP_BIT_RIGHT:
394 default:
395 order=ORDER_MSB;
396 }
397 if(RAW_decode(p_td, p_buf, p_buf.get_len()*8, order)<0)
398 ec.error(TTCN_EncDec::ET_INCOMPL_MSG,
399 "Can not decode type '%s', because invalid or incomplete"
400 " message was received"
401 , p_td.name);
402 break;}
403 case TTCN_EncDec::CT_XER: {
af710487 404 TTCN_EncDec_ErrorContext ec("While XER-decoding type '%s': ", p_td.name);
970ed795
EL
405 unsigned XER_coding=va_arg(pvar, unsigned);
406 XmlReaderWrap reader(p_buf);
407 for (int success = reader.Read(); success==1; success=reader.Read()) {
408 int type = reader.NodeType();
409 if (type==XML_READER_TYPE_ELEMENT)
410 break;
411 }
feade998 412 XER_decode(*p_td.xer, reader, XER_coding, XER_NONE, 0);
970ed795
EL
413 size_t bytes = reader.ByteConsumed();
414 p_buf.set_pos(bytes);
415 break;}
416 case TTCN_EncDec::CT_JSON: {
417 TTCN_EncDec_ErrorContext ec("While JSON-decoding type '%s': ", p_td.name);
418 if(!p_td.json)
419 TTCN_EncDec_ErrorContext::error_internal
420 ("No JSON descriptor available for type '%s'.", p_td.name);
421 JSON_Tokenizer tok((const char*)p_buf.get_data(), p_buf.get_len());
422 if(JSON_decode(p_td, tok, false)<0)
423 ec.error(TTCN_EncDec::ET_INCOMPL_MSG,
424 "Can not decode type '%s', because invalid or incomplete"
425 " message was received"
426 , p_td.name);
427 p_buf.set_pos(tok.get_buf_pos());
428 break;}
429 default:
430 TTCN_error("Unknown coding method requested to decode type '%s'",
431 p_td.name);
432 }
433 va_end(pvar);
434}
435
436ASN_BER_TLV_t*
437FLOAT::BER_encode_TLV(const TTCN_Typedescriptor_t& p_td,
438 unsigned p_coding) const
439{
440 BER_chk_descr(p_td);
441 ASN_BER_TLV_t *new_tlv=BER_encode_chk_bound(is_bound());
442 if(!new_tlv) {
443 if(float_value==0.0) {
444 new_tlv=ASN_BER_TLV_t::construct();
445 // nothing to do, Vlen is 0
446 }
447 /* +Infinity */
448 else if(float_value==(double)INFINITY) { // INFINITY may be float => cast
449 new_tlv=ASN_BER_TLV_t::construct(1, NULL);
450 new_tlv->V.str.Vstr[0]=0x40;
451 }
452 /* -Infinity */
453 else if(float_value==-(double)INFINITY) {
454 new_tlv=ASN_BER_TLV_t::construct(1, NULL);
455 new_tlv->V.str.Vstr[0]=0x41;
456 }
457 else if(isnan((double)float_value)) {
458 TTCN_EncDec_ErrorContext::error_internal("Value is NaN.");
459 }
460 else {
461 new_tlv=ASN_BER_TLV_t::construct();
462 double mantissa, exponent;
463 exponent=floor(log10(fabs(float_value)))+1.0-DBL_DIG;
464 mantissa=floor(float_value*pow(10.0,-exponent)+0.5);
465 if(mantissa)while(!fmod(mantissa,10.0))mantissa/=10.0,exponent+=1.0;
466 /** \todo review
467 gcc 2.95:
468 in mprintf below:
469 warning: `.' not followed by `*' or digit in format
470 */
471 new_tlv->V.str.Vstr=(unsigned char*)
472 mprintf("\x03%.f.E%s%.0f", mantissa, exponent==0.0?"+":"", exponent);
473 new_tlv->V.str.Vlen=1+strlen((const char*)&new_tlv->V.str.Vstr[1]);
474 }
475 }
476 new_tlv=ASN_BER_V2TLV(new_tlv, p_td, p_coding);
477 return new_tlv;
478}
479
480boolean FLOAT::BER_decode_TLV(const TTCN_Typedescriptor_t& p_td,
481 const ASN_BER_TLV_t& p_tlv,
482 unsigned L_form)
483{
484 bound_flag = FALSE;
485 BER_chk_descr(p_td);
486 ASN_BER_TLV_t stripped_tlv;
487 BER_decode_strip_tags(*p_td.ber, p_tlv, L_form, stripped_tlv);
488 TTCN_EncDec_ErrorContext ec("While decoding REAL type: ");
489 stripped_tlv.chk_constructed_flag(FALSE);
490 if (!stripped_tlv.isComplete) return FALSE;
491 size_t Vlen=stripped_tlv.V.str.Vlen;
492 unsigned char *Vstr=stripped_tlv.V.str.Vstr;
493 if(Vlen==0) {
494 float_value=0.0;
495 }
496 else if(Vstr[0] & 0x80) {
497 /* binary encoding */
498 /** \todo Perhaps it were good to implement this. Perhaps not. :) */
499 ec.warning("Sorry, decoding of binary encoded REAL values not"
500 " supported.");
501 float_value=0.0;
502 }
503 else if(Vstr[0] & 0x40) {
504 /* SpecialRealValue */
505 if(Vlen>1)
506 ec.error(TTCN_EncDec::ET_INVAL_MSG,
507 "In case of SpecialRealValue, the length of V-part must be 1"
508 " (See X.690 8.5.8).");
509 if(Vstr[0] & 0x3E)
510 ec.error(TTCN_EncDec::ET_INVAL_MSG,
511 "This is a reserved value: 0x%x (See X.690 8.5.8).",
512 Vstr[0]);
513 if(Vstr[0] & 0x01)
514 /* MINUS-INFINITY */
515 float_value=-INFINITY;
516 else
517 /* PLUS-INFINITY */
518 float_value=INFINITY;
519 }
520 else {
521 /* decimal encoding */
522 if((Vstr[0] & 0x3C) || (Vstr[0] & 0x3F) == 0x00 )
523 ec.error(TTCN_EncDec::ET_INVAL_MSG,
524 "This is a reserved value: 0x%x (See X.690 8.5.7).",
525 Vstr[0]);
526 int NR=Vstr[0] & 0x03; // which NumericalRepresentation
527 boolean
528 leadingzero=FALSE,
529 NR_error=FALSE;
530 unsigned char
531 *Vstr_last=Vstr+Vlen-1,
532 *sign=NULL,
533 *mant1=NULL,
534 *decmark=NULL,
535 *mant2=NULL,
536 *expmark=NULL,
537 *expsign=NULL,
538 *expo=NULL,
539 *ptr=Vstr+1;
540 size_t
541 mant1_len=0,
542 mant2_len=0,
543 expo_len=0;
544 long exponum;
545 if(Vlen==1) goto dec_error;
546 while(*ptr==' ') {
547 if(ptr==Vstr_last) goto dec_error;
548 ptr++;
549 }
550 if(*ptr=='+' || *ptr=='-') {
551 sign=ptr;
552 if(ptr==Vstr_last) goto dec_error;
553 ptr++;
554 }
555 while(*ptr=='0') {
556 leadingzero=TRUE;
557 if(ptr==Vstr_last) goto str_end;
558 ptr++;
559 }
560 while(*ptr>='0' && *ptr<='9') {
561 if(mant1_len==0) mant1=ptr;
562 mant1_len++;
563 if(ptr==Vstr_last) goto str_end;
564 ptr++;
565 }
566 if(*ptr=='.' || *ptr==',') {
567 decmark=ptr;
568 if(ptr==Vstr_last) goto str_end;
569 ptr++;
570 }
571 while(*ptr>='0' && *ptr<='9') {
572 if(mant2_len==0) mant2=ptr;
573 mant2_len++;
574 if(ptr==Vstr_last) goto str_end;
575 ptr++;
576 }
577 if(!leadingzero && !mant1 && !mant2) goto dec_error;
578 if(*ptr=='e' || *ptr=='E') {
579 expmark=ptr;
580 if(ptr==Vstr_last) goto dec_error;
581 ptr++;
582 }
583 if(*ptr=='+' || *ptr=='-') {
584 expsign=ptr;
585 if(ptr==Vstr_last) goto dec_error;
586 ptr++;
587 }
588 while(*ptr=='0') {
589 expo=ptr;
590 if(ptr==Vstr_last) goto str_end;
591 ptr++;
592 }
593 while(*ptr>='0' && *ptr<='9') {
594 if(expo_len==0) expo=ptr;
595 expo_len++;
596 if(ptr==Vstr_last) goto str_end;
597 ptr++;
598 }
599 if(expo_len==0 && expo!=NULL) expo_len=1; /* only leading zero */
600 if(expsign && !expo) goto dec_error;
601 ec.error(TTCN_EncDec::ET_INVAL_MSG,
602 "Superfluous part at the end of decimal encoding.");
603 str_end:
604 /* check NR */
605 if(NR==1) {
606 if(decmark || expmark) NR_error=TRUE;
607 }
608 else if(NR==2) {
609 if(expmark) NR_error=TRUE;
610 }
611 if(NR_error)
612 ec.error(TTCN_EncDec::ET_INVAL_MSG,
613 "This decimal encoding does not conform to NR%d form.", NR);
614 while(mant2_len>1 && mant2[mant2_len-1]=='0') mant2_len--;
615 if(mant2_len==1 && *mant2=='0') mant2_len=0, mant2=NULL;
616 float_value=0.0;
617 if(mant1) for(size_t i=0; i<mant1_len; i++) {
618 float_value*=10.0;
619 float_value+=static_cast<double>(mant1[i]-'0');
620 } // for i if...
621 if(mant2) for(size_t i=0; i<mant2_len; i++) {
622 float_value*=10.0;
623 float_value+=static_cast<double>(mant2[i]-'0');
624 } // for i if...
625 exponum=0;
626 if(expo) {
627 if(ceil(log10(log10(DBL_MAX)))<expo_len) {
628 /* overflow */
629 if(expsign && *expsign=='-') {
630 float_value=0.0;
631 }
632 else {
633 if(sign && *sign=='-') float_value=-INFINITY;
634 else float_value=INFINITY;
635 }
636 goto end;
637 } // overflow
638 else {
639 /* no overflow */
640 for(size_t i=0; i<expo_len; i++) {
641 exponum*=10;
642 exponum+=static_cast<int>(expo[i]-'0');
643 } // for i
644 if(expsign && *expsign=='-')
645 exponum*=-1;
646 } // no overflow
647 } // if expo
648 if(mant2) exponum-=mant2_len;
649 float_value*=pow(10.0, static_cast<double>(exponum));
650 goto end;
651 dec_error:
652 ec.error(TTCN_EncDec::ET_INVAL_MSG, "Erroneous decimal encoding.");
653 float_value=0.0;
654 }
655 end:
656 bound_flag=TRUE;
657 return TRUE;
658}
659
660int FLOAT::RAW_encode(const TTCN_Typedescriptor_t& p_td, RAW_enc_tree& myleaf) const
661{
662 unsigned char *bc;
663 unsigned char *dv;
664 int length = p_td.raw->fieldlength / 8;
665 double tmp = float_value;
666 if (!is_bound()) {
667 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,
668 "Encoding an unbound value.");
669 tmp = 0.0;
670 }
671 if (isnan(tmp)) {
672 TTCN_EncDec_ErrorContext::error_internal("Value is NaN.");
673 }
674 if (myleaf.must_free) Free(myleaf.body.leaf.data_ptr);
675 if (length > RAW_INT_ENC_LENGTH) {
676 myleaf.body.leaf.data_ptr = bc = (unsigned char*)Malloc(length*sizeof(*bc));
677 myleaf.must_free = TRUE;
678 myleaf.data_ptr_used = TRUE;
679 }
680 else {
681 bc = myleaf.body.leaf.data_array;
682 }
683 if (length == 8) {
684 dv = (unsigned char *) &tmp;
685#if defined __sparc__ || defined __sparc
686 memcpy(bc,dv,8);
687#else
688 for (int i = 0, k = 7; i < 8; i++, k--) bc[i] = dv[k];
689#endif
690 }
691 else if (length == 4) {
692 if (tmp == 0.0) memset(bc, 0, 4);
693 else if (tmp == -0.0) {
694 memset(bc, 0, 4);
695 bc[0] |= 0x80;
696 }
697 else {
698#if defined __sparc__ || defined __sparc
699 int index=0;
700 int adj=1;
701#else
702 int index = 7;
703 int adj = -1;
704#endif
705 dv = (unsigned char *) &tmp;
706 bc[0] = dv[index] & 0x80;
707 int exponent = dv[index] & 0x7F;
708 exponent <<= 4;
709 index += adj;
710 exponent += (dv[index] & 0xF0) >> 4;
711 exponent -= 1023;
712
713 if (exponent > 127) {
714 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR,
715 "The float value '%f' is out of the range of "
716 "the single precision: %s", (double)float_value, p_td.name);
717 tmp = 0.0;
718 exponent = 0;
719 }
720 else if (exponent < -127) {
721 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_FLOAT_TR,
722 "The float value '%f' is too small to represent it "
723 "in single precision: %s", (double)float_value, p_td.name);
724 tmp = 0.0;
725 exponent = 0;
726 }
727 else exponent += 127;
728 bc[0] |= (exponent >> 1) & 0x7F;
729 bc[1] = ((exponent << 7) & 0x80) | ((dv[index] & 0x0F) << 3)
730 | ((dv[index + adj] & 0xE0) >> 5);
731 index += adj;
732 bc[2] = ((dv[index] & 0x1F) << 3) | ((dv[index + adj] & 0xE0) >> 5);
733 index += adj;
734 bc[3] = ((dv[index] & 0x1F) << 3) | ((dv[index + adj] & 0xE0) >> 5);
735 }
736 }
737 else
738 TTCN_EncDec_ErrorContext::error_internal("Invalid FLOAT length %d", length);
739
740 return myleaf.length = p_td.raw->fieldlength;
741}
742
743int FLOAT::RAW_decode(const TTCN_Typedescriptor_t& p_td, TTCN_Buffer& buff,
744 int limit, raw_order_t top_bit_ord, boolean no_err, int /*sel_field*/,
745 boolean /*first_call*/)
746{
747 int prepaddlength = buff.increase_pos_padd(p_td.raw->prepadding);
748 unsigned char *dv;
749 limit -= prepaddlength;
750 int decode_length = p_td.raw->fieldlength;
751 if ( p_td.raw->fieldlength > limit
752 || p_td.raw->fieldlength > (int) buff.unread_len_bit()) {
753 if (no_err) return -1;
754 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR,
755 "There is not enough bits in the buffer to decode type %s.", p_td.name);
756 decode_length = limit > (int) buff.unread_len_bit()
757 ? buff.unread_len_bit() : limit;
758 bound_flag = TRUE;
759 float_value = 0.0;
760 decode_length += buff.increase_pos_padd(p_td.raw->padding);
761 return decode_length + prepaddlength;
762 }
763 double tmp = 0.0;
764 unsigned char data[16];
765 RAW_coding_par cp;
766 boolean orders = FALSE;
767 if (p_td.raw->bitorderinoctet == ORDER_MSB) orders = TRUE;
768 if (p_td.raw->bitorderinfield == ORDER_MSB) orders = !orders;
769 cp.bitorder = orders ? ORDER_MSB : ORDER_LSB;
770 orders = FALSE;
771 if (p_td.raw->byteorder == ORDER_MSB) orders = TRUE;
772 if (p_td.raw->bitorderinfield == ORDER_MSB) orders = !orders;
773 cp.byteorder = orders ? ORDER_MSB : ORDER_LSB;
774 cp.fieldorder = p_td.raw->fieldorder;
775 cp.hexorder = ORDER_LSB;
776 buff.get_b((size_t) decode_length, data, cp, top_bit_ord);
777 if (decode_length == 64) {
778 dv = (unsigned char *) &tmp;
779#if defined __sparc__ || defined __sparc
780 memcpy(dv,data,8);
781#else
782 for (int i = 0, k = 7; i < 8; i++, k--) dv[i] = data[k];
783#endif
784 if (isnan(tmp)) {
785 if (no_err) return -1;
786 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR,
787 "Not a Number received for type %s.", p_td.name);
788 tmp = 0.0;
789 }
790 }
791 else if (decode_length == 32) {
792 int sign = (data[0] & 0x80) >> 7;
793 int exponent = ((data[0] & 0x7F) << 1) | ((data[1] & 0x80) >> 7);
794 int fraction = ((data[1] & 0x7F) << 1) | ((data[2] & 0x80) >> 7);
795 fraction <<= 8;
796 fraction += ((data[2] & 0x7F) << 1) | ((data[3] & 0x80) >> 7);
797 fraction <<= 7;
798 fraction += data[3] & 0x7F;
799 if (exponent == 0 && fraction == 0) tmp = sign ? -0.0 : 0.0;
800 else if (exponent == 0xFF && fraction != 0) {
801 if (no_err) return -1;
802 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR,
803 "Not a Number received for type %s.", p_td.name);
804 tmp = 0.0;
805 }
806 else if (exponent == 0 && fraction != 0) {
807 double sign_v = sign ? -1.0 : 1.0;
808 tmp = sign_v * (static_cast<double> (fraction) / 8388608.0)
809 * pow(2.0, -126.0);
810 }
811 else {
812 double sign_v = sign ? -1.0 : 1.0;
813 exponent -= 127;
814 tmp = sign_v * (1.0 + static_cast<double> (fraction) / 8388608.0)
815 * pow(2.0, static_cast<double> (exponent));
816 }
817
818 }
819 decode_length += buff.increase_pos_padd(p_td.raw->padding);
820 bound_flag = TRUE;
821 float_value = tmp;
822 return decode_length + prepaddlength;
823}
824
825int FLOAT::XER_encode(const XERdescriptor_t& p_td,
af710487 826 TTCN_Buffer& p_buf, unsigned int flavor, int indent, embed_values_enc_struct_t*) const
970ed795
EL
827{
828 if(!is_bound()) {
829 TTCN_EncDec_ErrorContext::error(
830 TTCN_EncDec::ET_UNBOUND, "Encoding an unbound float value.");
831 }
832 int exer = is_exer(flavor |= SIMPLE_TYPE);
833 // SIMPLE_TYPE has no influence on is_exer, we set it for later
834 int encoded_length=(int)p_buf.get_len();
835 flavor &= ~XER_RECOF; // float doesn't care
836
837 begin_xml(p_td, p_buf, flavor, indent, false);
838
839 if (exer && (p_td.xer_bits & XER_DECIMAL)) {
840 char buf[312];
841 int n = snprintf(buf, sizeof(buf), "%f", (double)float_value);
842 p_buf.put_s((size_t)n, (const unsigned char*)buf);
843 }
844 else {
845 CHARSTRING value = float2str(float_value);
846 p_buf.put_string(value);
847 }
848
849 end_xml(p_td, p_buf, flavor, indent, false);
850
851 return (int)p_buf.get_len() - encoded_length;
852}
853
a38c6d4c 854boolean FLOAT::is_float(const char* p_str)
855{
856 bool first_digit = false; // first digit reached
857 bool decimal_point = false; // decimal point (.) reached
858 bool exponent_mark = false; // exponential mark (e or E) reached
859 bool exponent_sign = false; // sign of the exponential (- or +) reached
860
861 if ('-' == *p_str || '+' == *p_str) {
862 ++p_str;
863 }
864
865 while (0 != *p_str) {
866 switch(*p_str) {
867 case '.':
868 if (decimal_point || exponent_mark || !first_digit) {
869 return false;
870 }
871 decimal_point = true;
872 first_digit = false;
873 break;
874 case 'e':
875 case 'E':
876 if (exponent_mark || !first_digit) {
877 return false;
878 }
879 exponent_mark = true;
880 first_digit = false;
881 break;
882 case '0':
883 case '1':
884 case '2':
885 case '3':
886 case '4':
887 case '5':
888 case '6':
889 case '7':
890 case '8':
891 case '9':
892 first_digit = true;
893 break;
894 case '-':
895 case '+':
896 if (exponent_sign || !exponent_mark || first_digit) {
897 return false;
898 }
899 exponent_sign = true;
900 break;
901 default:
902 return false;
903 }
904
905 ++p_str;
906 }
907 return first_digit;
908}
909
970ed795 910int FLOAT::XER_decode(const XERdescriptor_t& p_td, XmlReaderWrap& reader,
feade998 911 unsigned int flavor, unsigned int /*flavor2*/, embed_values_dec_struct_t*)
970ed795 912{
a38c6d4c 913 bound_flag = false;
970ed795
EL
914 int exer = is_exer(flavor);
915 int success = reader.Ok(), depth = -1;
916 if (success <= 0) return 0;
917 boolean own_tag = !(exer && (p_td.xer_bits & UNTAGGED)) && !is_exerlist(flavor);
918
919 if (!own_tag) goto tagless;
920 if (exer && (p_td.xer_bits & XER_ATTRIBUTE)) {
921 verify_name(reader, p_td, exer);
922tagless:
923 const char * value = (const char *)reader.Value();
924
a38c6d4c 925 if (value && is_float(value)) {
970ed795 926 bound_flag = true;
a38c6d4c 927 sscanf(value, "%lf", &float_value);
928 }
970ed795
EL
929
930 // Let the caller do reader.AdvanceAttribute();
931 }
932 else {
933 for (; success == 1; success = reader.Read()) {
934 int type = reader.NodeType();
935 if (XML_READER_TYPE_ELEMENT == type) {
936 verify_name(reader, p_td, exer);
937 if (reader.IsEmptyElement()) {
938 if (exer && p_td.dfeValue != 0) {
939 *this = *static_cast<const FLOAT*>(p_td.dfeValue);
940 }
941 reader.Read();
942 break;
943 }
944 depth = reader.Depth();
945 }
946 else if (XML_READER_TYPE_TEXT == type && depth != -1) {
947 const char * value = (const char*)reader.Value();
a38c6d4c 948 if (value && is_float(value)) {
970ed795 949 bound_flag = true;
a38c6d4c 950 sscanf(value, "%lf", &float_value);
951 }
970ed795
EL
952 }
953 else if (XML_READER_TYPE_END_ELEMENT == type) {
954 verify_end(reader, p_td, depth, exer);
955 if (!bound_flag && exer && p_td.dfeValue != 0) {
956 *this = *static_cast<const FLOAT*>(p_td.dfeValue);
957 }
958 reader.Read();
959 break;
960 }
961 } // next read
962 } // if not attribute
963 return 1; // decode successful
964}
965
966const char* POS_INF_STR = "\"infinity\"";
967const char* NEG_INF_STR = "\"-infinity\"";
968const char* NAN_STR = "\"not_a_number\"";
969
970int FLOAT::JSON_encode(const TTCN_Typedescriptor_t&, JSON_Tokenizer& p_tok) const
971{
972 if (!is_bound()) {
973 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND,
974 "Encoding an unbound float value.");
975 return -1;
976 }
977
978 double value = (double)float_value;
979 if ((double)INFINITY == value) {
980 return p_tok.put_next_token(JSON_TOKEN_STRING, POS_INF_STR);
981 }
982 if (-(double)INFINITY == value) {
983 return p_tok.put_next_token(JSON_TOKEN_STRING, NEG_INF_STR);
984 }
985 if (isnan(value)) {
986 return p_tok.put_next_token(JSON_TOKEN_STRING, NAN_STR);
987 }
988
989 // true if decimal representation possible (use %f format)
990 bool decimal_repr = (value == 0.0)
991 || (value > -MAX_DECIMAL_FLOAT && value <= -MIN_DECIMAL_FLOAT)
992 || (value >= MIN_DECIMAL_FLOAT && value < MAX_DECIMAL_FLOAT);
993
994 char* tmp_str = mprintf(decimal_repr ? "%f" : "%e", value);
995 int enc_len = p_tok.put_next_token(JSON_TOKEN_NUMBER, tmp_str);
996 Free(tmp_str);
997 return enc_len;
998}
999
1000int FLOAT::JSON_decode(const TTCN_Typedescriptor_t& p_td, JSON_Tokenizer& p_tok, boolean p_silent)
1001{
1002 bound_flag = false;
1003 json_token_t token = JSON_TOKEN_NONE;
1004 char* value = 0;
1005 size_t value_len = 0;
1006 int dec_len = 0;
1007 boolean use_default = p_td.json->default_value && 0 == p_tok.get_buffer_length();
1008 if (use_default) {
1009 // No JSON data in the buffer -> use default value
1010 value = (char*)p_td.json->default_value;
1011 value_len = strlen(value);
1012 } else {
1013 dec_len = p_tok.get_next_token(&token, &value, &value_len);
1014 }
1015 if (JSON_TOKEN_ERROR == token) {
1016 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_BAD_TOKEN_ERROR, "");
1017 return JSON_ERROR_FATAL;
1018 }
1019 else if (JSON_TOKEN_STRING == token || use_default) {
1020 if (0 == strncmp(value, POS_INF_STR + (use_default ? 1 : 0), value_len)) {
1021 bound_flag = true;
1022 float_value = INFINITY;
1023 }
1024 else if (0 == strncmp(value, NEG_INF_STR + (use_default ? 1 : 0), value_len)) {
1025 bound_flag = true;
1026 float_value = -INFINITY;
1027 }
1028 else if (0 == strncmp(value, NAN_STR + (use_default ? 1 : 0), value_len)) {
1029 bound_flag = true;
1030#ifdef NAN
1031 float_value = NAN;
1032#else
1033 float_value = INFINITY + (-INFINITY);
1034#endif
1035 }
1036 else if (!use_default) {
1037 char* spec_val = mprintf("float (%s, %s or %s)", POS_INF_STR, NEG_INF_STR, NAN_STR);
1038 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG, JSON_DEC_FORMAT_ERROR, "string", spec_val);
1039 Free(spec_val);
1040 bound_flag = false;
1041 return JSON_ERROR_FATAL;
1042 }
1043 }
1044 else if (JSON_TOKEN_NUMBER == token) {
1045 char* value2 = mcopystrn(value, value_len);
1046 sscanf(value2, "%lf", &float_value);
1047 bound_flag = true;
1048 Free(value2);
1049 } else {
1050 return JSON_ERROR_INVALID_TOKEN;
1051 }
1052 if (!bound_flag && use_default) {
1053 // Already checked the default value for the string possibilities, now
1054 // check for a valid number
1055 char* value2 = mcopystrn(value, value_len);
1056 sscanf(value2, "%lf", &float_value);
1057 bound_flag = true;
1058 Free(value2);
1059 }
1060 return dec_len;
1061}
1062
1063
1064// global functions
1065
1066double operator+(double double_value, const FLOAT& other_value)
1067{
1068 other_value.must_bound("Unbound right operand of float addition.");
1069 FLOAT::check_numeric(double_value, "Left operand of float addition");
1070 FLOAT::check_numeric(other_value.float_value, "Right operand of float addition");
1071 return double_value + other_value.float_value;
1072}
1073
1074double operator-(double double_value, const FLOAT& other_value)
1075{
1076 other_value.must_bound("Unbound right operand of float subtraction.");
1077 FLOAT::check_numeric(double_value, "Left operand of float subtraction");
1078 FLOAT::check_numeric(other_value.float_value, "Right operand of float subtraction");
1079 return double_value - other_value.float_value;
1080}
1081
1082double operator*(double double_value, const FLOAT& other_value)
1083{
1084 other_value.must_bound("Unbound right operand of float multiplication.");
1085 FLOAT::check_numeric(double_value, "Left operand of float multiplication");
1086 FLOAT::check_numeric(other_value.float_value, "Right operand of float multiplication");
1087 return double_value * other_value.float_value;
1088}
1089
1090double operator/(double double_value, const FLOAT& other_value)
1091{
1092 other_value.must_bound("Unbound right operand of float division.");
1093 FLOAT::check_numeric(double_value, "Left operand of float division");
1094 FLOAT::check_numeric(other_value.float_value, "Right operand of float division");
1095 if (other_value.float_value == 0.0) TTCN_error("Float division by zero.");
1096 return double_value / other_value.float_value;
1097}
1098
1099boolean operator==(double double_value, const FLOAT& other_value)
1100{
1101 other_value.must_bound("Unbound right operand of float comparison.");
1102 return double_value == other_value.float_value;
1103}
1104
1105boolean operator<(double double_value, const FLOAT& other_value)
1106{
1107 other_value.must_bound("Unbound right operand of float comparison.");
1108 return double_value < other_value.float_value;
1109}
1110
1111boolean operator>(double double_value, const FLOAT& other_value)
1112{
1113 other_value.must_bound("Unbound right operand of float comparison.");
1114 return double_value > other_value.float_value;
1115}
1116
1117// float template class
1118
1119void FLOAT_template::clean_up()
1120{
1121 if (template_selection == VALUE_LIST ||
1122 template_selection == COMPLEMENTED_LIST)
1123 delete [] value_list.list_value;
1124 template_selection = UNINITIALIZED_TEMPLATE;
1125}
1126
1127void FLOAT_template::copy_template(const FLOAT_template& other_value)
1128{
1129 switch (other_value.template_selection) {
1130 case SPECIFIC_VALUE:
1131 single_value = other_value.single_value;
1132 break;
1133 case OMIT_VALUE:
1134 case ANY_VALUE:
1135 case ANY_OR_OMIT:
1136 break;
1137 case VALUE_LIST:
1138 case COMPLEMENTED_LIST:
1139 value_list.n_values = other_value.value_list.n_values;
1140 value_list.list_value = new FLOAT_template[value_list.n_values];
1141 for (unsigned int i = 0; i < value_list.n_values; i++)
1142 value_list.list_value[i].copy_template(
1143 other_value.value_list.list_value[i]);
1144 break;
1145 case VALUE_RANGE:
1146 value_range = other_value.value_range;
1147 break;
1148 default:
1149 TTCN_error("Copying an uninitialized/unsupported float template.");
1150 }
1151 set_selection(other_value);
1152}
1153
1154FLOAT_template::FLOAT_template()
1155{
1156
1157}
1158
1159FLOAT_template::FLOAT_template(template_sel other_value)
1160 : Base_Template(other_value)
1161{
1162 check_single_selection(other_value);
1163}
1164
1165FLOAT_template::FLOAT_template(double other_value)
1166 : Base_Template(SPECIFIC_VALUE)
1167{
1168 single_value = other_value;
1169}
1170
1171FLOAT_template::FLOAT_template(const FLOAT& other_value)
1172 : Base_Template(SPECIFIC_VALUE)
1173{
1174 other_value.must_bound("Creating a template from an unbound float value.");
1175 single_value = other_value.float_value;
1176}
1177
1178FLOAT_template::FLOAT_template(const OPTIONAL<FLOAT>& other_value)
1179{
1180 switch (other_value.get_selection()) {
1181 case OPTIONAL_PRESENT:
1182 set_selection(SPECIFIC_VALUE);
1183 single_value = (double)(const FLOAT&)other_value;
1184 break;
1185 case OPTIONAL_OMIT:
1186 set_selection(OMIT_VALUE);
1187 break;
1188 default:
1189 TTCN_error("Creating a float template from an unbound optional field.");
1190 }
1191}
1192
1193FLOAT_template::FLOAT_template(const FLOAT_template& other_value)
1194: Base_Template()
1195{
1196 copy_template(other_value);
1197}
1198
1199FLOAT_template::~FLOAT_template()
1200{
1201 clean_up();
1202}
1203
1204FLOAT_template& FLOAT_template::operator=(template_sel other_value)
1205{
1206 check_single_selection(other_value);
1207 clean_up();
1208 set_selection(other_value);
1209 return *this;
1210}
1211
1212FLOAT_template& FLOAT_template::operator=(double other_value)
1213{
1214 clean_up();
1215 set_selection(SPECIFIC_VALUE);
1216 single_value = other_value;
1217 return *this;
1218}
1219
1220FLOAT_template& FLOAT_template::operator=(const FLOAT& other_value)
1221{
1222 other_value.must_bound("Assignment of an unbound float value "
1223 "to a template.");
1224 clean_up();
1225 set_selection(SPECIFIC_VALUE);
1226 single_value = other_value.float_value;
1227 return *this;
1228}
1229
1230FLOAT_template& FLOAT_template::operator=(const OPTIONAL<FLOAT>& other_value)
1231{
1232 clean_up();
1233 switch (other_value.get_selection()) {
1234 case OPTIONAL_PRESENT:
1235 set_selection(SPECIFIC_VALUE);
1236 single_value = (double)(const FLOAT&)other_value;
1237 break;
1238 case OPTIONAL_OMIT:
1239 set_selection(OMIT_VALUE);
1240 break;
1241 default:
1242 TTCN_error("Assignment of an unbound optional field to a float template.");
1243 }
1244 return *this;
1245}
1246
1247FLOAT_template& FLOAT_template::operator=(const FLOAT_template& other_value)
1248{
1249 if (&other_value != this) {
1250 clean_up();
1251 copy_template(other_value);
1252 }
1253 return *this;
1254}
1255
3abe9331 1256boolean FLOAT_template::match(double other_value, boolean /* legacy */) const
970ed795
EL
1257{
1258 switch (template_selection) {
1259 case SPECIFIC_VALUE:
3abe9331 1260 return single_value == other_value || // check if they're both NaN
1261 (single_value != single_value && other_value != other_value);
970ed795
EL
1262 case OMIT_VALUE:
1263 return FALSE;
1264 case ANY_VALUE:
1265 case ANY_OR_OMIT:
1266 return TRUE;
1267 case VALUE_LIST:
1268 case COMPLEMENTED_LIST:
1269 for (unsigned int i = 0; i < value_list.n_values; i++)
1270 if(value_list.list_value[i].match(other_value))
1271 return template_selection == VALUE_LIST;
1272 return template_selection == COMPLEMENTED_LIST;
1273 case VALUE_RANGE:
1274 return (!value_range.min_is_present ||
1275 value_range.min_value <= other_value) &&
1276 (!value_range.max_is_present ||
1277 value_range.max_value >= other_value);
1278 default:
1279 TTCN_error("Matching with an uninitialized/unsupported float template.");
1280 }
1281 return FALSE;
1282}
1283
3abe9331 1284boolean FLOAT_template::match(const FLOAT& other_value, boolean /* legacy */) const
970ed795
EL
1285{
1286 if (!other_value.is_bound()) return FALSE;
1287 return match(other_value.float_value);
1288}
1289
1290
1291void FLOAT_template::set_type(template_sel template_type,
1292 unsigned int list_length)
1293{
1294 clean_up();
1295 switch (template_type) {
1296 case VALUE_LIST:
1297 case COMPLEMENTED_LIST:
1298 set_selection(template_type);
1299 value_list.n_values = list_length;
1300 value_list.list_value = new FLOAT_template[list_length];
1301 break;
1302 case VALUE_RANGE:
1303 set_selection(VALUE_RANGE);
1304 value_range.min_is_present = FALSE;
1305 value_range.max_is_present = FALSE;
1306 break;
1307 default:
1308 TTCN_error("Setting an invalid type for a float template.");
1309 }
1310}
1311
1312FLOAT_template& FLOAT_template::list_item(unsigned int list_index)
1313{
1314 if (template_selection != VALUE_LIST &&
1315 template_selection != COMPLEMENTED_LIST)
1316 TTCN_error("Accessing a list element of a non-list float template.");
1317 if (list_index >= value_list.n_values)
1318 TTCN_error("Index overflow in a float value list template.");
1319 return value_list.list_value[list_index];
1320}
1321
1322void FLOAT_template::set_min(double min_value)
1323{
1324 if (template_selection != VALUE_RANGE)
1325 TTCN_error("Float template is not range when setting lower limit.");
1326 if (value_range.max_is_present && value_range.max_value < min_value)
1327 TTCN_error("The lower limit of the range is greater than the "
1328 "upper limit in a float template.");
1329 value_range.min_is_present = TRUE;
1330 value_range.min_value = min_value;
1331}
1332
1333void FLOAT_template::set_min(const FLOAT& min_value)
1334{
1335 min_value.must_bound("Using an unbound value when setting the lower bound "
1336 "in a float range template.");
1337 set_min(min_value.float_value);
1338}
1339
1340void FLOAT_template::set_max(double max_value)
1341{
1342 if (template_selection != VALUE_RANGE)
1343 TTCN_error("Float template is not range when setting upper limit.");
1344 if (value_range.min_is_present && value_range.min_value > max_value)
1345 TTCN_error("The upper limit of the range is smaller than the "
1346 "lower limit in a float template.");
1347 value_range.max_is_present = TRUE;
1348 value_range.max_value = max_value;
1349}
1350
1351void FLOAT_template::set_max(const FLOAT& max_value)
1352{
1353 max_value.must_bound("Using an unbound value when setting the upper bound "
1354 "in a float range template.");
1355 set_max(max_value.float_value);
1356}
1357
1358double FLOAT_template::valueof() const
1359{
1360 if (template_selection != SPECIFIC_VALUE || is_ifpresent)
1361 TTCN_error("Performing a valueof "
1362 "or send operation on a non-specific float template.");
1363 return single_value;
1364}
1365
1366void FLOAT_template::log() const
1367{
1368 switch (template_selection) {
1369 case SPECIFIC_VALUE:
1370 log_float(single_value);
1371 break;
1372 case COMPLEMENTED_LIST:
1373 TTCN_Logger::log_event_str("complement ");
1374 // no break
1375 case VALUE_LIST:
1376 TTCN_Logger::log_char('(');
1377 for (unsigned int i = 0; i < value_list.n_values; i++) {
1378 if (i > 0) TTCN_Logger::log_event_str(", ");
1379 value_list.list_value[i].log();
1380 }
1381 TTCN_Logger::log_char(')');
1382 break;
1383 case VALUE_RANGE:
1384 TTCN_Logger::log_char('(');
1385 if (value_range.min_is_present) log_float(value_range.min_value);
1386 else TTCN_Logger::log_event_str("-infinity");
1387 TTCN_Logger::log_event_str(" .. ");
1388 if (value_range.max_is_present) log_float(value_range.max_value);
1389 else TTCN_Logger::log_event_str("infinity");
1390 TTCN_Logger::log_char(')');
1391 break;
1392 default:
1393 log_generic();
1394 break;
1395 }
1396 log_ifpresent();
1397}
1398
3abe9331 1399void FLOAT_template::log_match(const FLOAT& match_value,
1400 boolean /* legacy */) const
970ed795
EL
1401{
1402 if (TTCN_Logger::VERBOSITY_COMPACT == TTCN_Logger::get_matching_verbosity()
1403 && TTCN_Logger::get_logmatch_buffer_len() != 0) {
1404 TTCN_Logger::print_logmatch_buffer();
1405 TTCN_Logger::log_event_str(" := ");
1406 }
1407 match_value.log();
1408 TTCN_Logger::log_event_str(" with ");
1409 log();
1410 if (match(match_value)) TTCN_Logger::log_event_str(" matched");
1411 else TTCN_Logger::log_event_str(" unmatched");
1412}
1413
1414void FLOAT_template::set_param(Module_Param& param) {
1415 param.basic_check(Module_Param::BC_TEMPLATE, "float template");
3abe9331 1416 Module_Param_Ptr mp = &param;
1417 if (param.get_type() == Module_Param::MP_Reference) {
1418 mp = param.get_referenced_param();
1419 }
1420 switch (mp->get_type()) {
970ed795
EL
1421 case Module_Param::MP_Omit:
1422 *this = OMIT_VALUE;
1423 break;
1424 case Module_Param::MP_Any:
1425 *this = ANY_VALUE;
1426 break;
1427 case Module_Param::MP_AnyOrNone:
1428 *this = ANY_OR_OMIT;
1429 break;
1430 case Module_Param::MP_List_Template:
3abe9331 1431 case Module_Param::MP_ComplementList_Template: {
1432 FLOAT_template temp;
1433 temp.set_type(mp->get_type() == Module_Param::MP_List_Template ?
1434 VALUE_LIST : COMPLEMENTED_LIST, mp->get_size());
1435 for (size_t i=0; i<mp->get_size(); i++) {
1436 temp.list_item(i).set_param(*mp->get_elem(i));
970ed795 1437 }
3abe9331 1438 *this = temp;
1439 break; }
970ed795 1440 case Module_Param::MP_Float:
3abe9331 1441 *this = mp->get_float();
970ed795
EL
1442 break;
1443 case Module_Param::MP_FloatRange:
1444 set_type(VALUE_RANGE);
3abe9331 1445 if (mp->has_lower_float()) set_min(mp->get_lower_float());
1446 if (mp->has_upper_float()) set_max(mp->get_upper_float());
1447 break;
1448 case Module_Param::MP_Expression:
1449 switch (mp->get_expr_type()) {
1450 case Module_Param::EXPR_NEGATE: {
1451 FLOAT operand;
1452 operand.set_param(*mp->get_operand1());
1453 *this = - operand;
1454 break; }
1455 case Module_Param::EXPR_ADD: {
1456 FLOAT operand1, operand2;
1457 operand1.set_param(*mp->get_operand1());
1458 operand2.set_param(*mp->get_operand2());
1459 *this = operand1 + operand2;
1460 break; }
1461 case Module_Param::EXPR_SUBTRACT: {
1462 FLOAT operand1, operand2;
1463 operand1.set_param(*mp->get_operand1());
1464 operand2.set_param(*mp->get_operand2());
1465 *this = operand1 - operand2;
1466 break; }
1467 case Module_Param::EXPR_MULTIPLY: {
1468 FLOAT operand1, operand2;
1469 operand1.set_param(*mp->get_operand1());
1470 operand2.set_param(*mp->get_operand2());
1471 *this = operand1 * operand2;
1472 break; }
1473 case Module_Param::EXPR_DIVIDE: {
1474 FLOAT operand1, operand2;
1475 operand1.set_param(*mp->get_operand1());
1476 operand2.set_param(*mp->get_operand2());
1477 if (operand2 == 0.0) {
1478 param.error("Floating point division by zero.");
1479 }
1480 *this = operand1 / operand2;
1481 break; }
1482 default:
1483 param.expr_type_error("a float");
1484 break;
1485 }
970ed795
EL
1486 break;
1487 default:
1488 param.type_error("float template");
1489 }
3abe9331 1490 is_ifpresent = param.get_ifpresent() || mp->get_ifpresent();
1491}
1492
1493Module_Param* FLOAT_template::get_param(Module_Param_Name& param_name) const
1494{
1495 Module_Param* mp = NULL;
1496 switch (template_selection) {
1497 case UNINITIALIZED_TEMPLATE:
1498 mp = new Module_Param_Unbound();
1499 break;
1500 case OMIT_VALUE:
1501 mp = new Module_Param_Omit();
1502 break;
1503 case ANY_VALUE:
1504 mp = new Module_Param_Any();
1505 break;
1506 case ANY_OR_OMIT:
1507 mp = new Module_Param_AnyOrNone();
1508 break;
1509 case SPECIFIC_VALUE:
1510 mp = new Module_Param_Float(single_value);
1511 break;
1512 case VALUE_LIST:
1513 case COMPLEMENTED_LIST: {
1514 if (template_selection == VALUE_LIST) {
1515 mp = new Module_Param_List_Template();
1516 }
1517 else {
1518 mp = new Module_Param_ComplementList_Template();
1519 }
1520 for (size_t i = 0; i < value_list.n_values; ++i) {
1521 mp->add_elem(value_list.list_value[i].get_param(param_name));
1522 }
1523 break; }
1524 case VALUE_RANGE:
1525 mp = new Module_Param_FloatRange(
1526 value_range.min_value, value_range.min_is_present,
1527 value_range.max_value, value_range.max_is_present);
1528 break;
1529 default:
1530 break;
1531 }
1532 if (is_ifpresent) {
1533 mp->set_ifpresent();
1534 }
1535 return mp;
970ed795
EL
1536}
1537
1538void FLOAT_template::encode_text(Text_Buf& text_buf) const
1539{
1540 encode_text_base(text_buf);
1541 switch (template_selection) {
1542 case OMIT_VALUE:
1543 case ANY_VALUE:
1544 case ANY_OR_OMIT:
1545 break;
1546 case SPECIFIC_VALUE:
1547 text_buf.push_double(single_value);
1548 break;
1549 case VALUE_LIST:
1550 case COMPLEMENTED_LIST:
1551 text_buf.push_int(value_list.n_values);
1552 for (unsigned int i = 0; i < value_list.n_values; i++)
1553 value_list.list_value[i].encode_text(text_buf);
1554 break;
1555 case VALUE_RANGE:
1556 text_buf.push_int(value_range.min_is_present ? 1 : 0);
1557 if (value_range.min_is_present)
1558 text_buf.push_double(value_range.min_value);
1559 text_buf.push_int(value_range.max_is_present ? 1 : 0);
1560 if (value_range.max_is_present)
1561 text_buf.push_double(value_range.max_value);
1562 break;
1563 default:
1564 TTCN_error("Text encoder: Encoding an undefined/unsupported "
1565 "float template.");
1566 }
1567}
1568
1569void FLOAT_template::decode_text(Text_Buf& text_buf)
1570{
1571 clean_up();
1572 decode_text_base(text_buf);
1573 switch (template_selection) {
1574 case OMIT_VALUE:
1575 case ANY_VALUE:
1576 case ANY_OR_OMIT:
1577 break;
1578 case SPECIFIC_VALUE:
1579 single_value = text_buf.pull_double();
1580 break;
1581 case VALUE_LIST:
1582 case COMPLEMENTED_LIST:
1583 value_list.n_values = text_buf.pull_int().get_val();
1584 value_list.list_value = new FLOAT_template[value_list.n_values];
1585 for (unsigned int i = 0; i < value_list.n_values; i++)
1586 value_list.list_value[i].decode_text(text_buf);
1587 break;
1588 case VALUE_RANGE:
1589 value_range.min_is_present = text_buf.pull_int() != 0;
1590 if (value_range.min_is_present)
1591 value_range.min_value = text_buf.pull_double();
1592 value_range.max_is_present = text_buf.pull_int() != 0;
1593 if (value_range.max_is_present)
1594 value_range.max_value = text_buf.pull_double();
1595 break;
1596 default:
1597 TTCN_error("Text decoder: An unknown/unsupported selection was "
1598 "received for a float template.");
1599 }
1600}
1601
3abe9331 1602boolean FLOAT_template::is_present(boolean legacy /* = FALSE */) const
970ed795
EL
1603{
1604 if (template_selection==UNINITIALIZED_TEMPLATE) return FALSE;
3abe9331 1605 return !match_omit(legacy);
970ed795
EL
1606}
1607
3abe9331 1608boolean FLOAT_template::match_omit(boolean legacy /* = FALSE */) const
970ed795
EL
1609{
1610 if (is_ifpresent) return TRUE;
1611 switch (template_selection) {
1612 case OMIT_VALUE:
1613 case ANY_OR_OMIT:
1614 return TRUE;
1615 case VALUE_LIST:
1616 case COMPLEMENTED_LIST:
3abe9331 1617 if (legacy) {
1618 // legacy behavior: 'omit' can appear in the value/complement list
1619 for (unsigned int i=0; i<value_list.n_values; i++)
1620 if (value_list.list_value[i].match_omit())
1621 return template_selection==VALUE_LIST;
1622 return template_selection==COMPLEMENTED_LIST;
1623 }
1624 // else fall through
970ed795
EL
1625 default:
1626 return FALSE;
1627 }
1628 return FALSE;
1629}
1630
1631#ifndef TITAN_RUNTIME_2
3abe9331 1632void FLOAT_template::check_restriction(template_res t_res, const char* t_name,
1633 boolean legacy /* = FALSE */) const
970ed795
EL
1634{
1635 if (template_selection==UNINITIALIZED_TEMPLATE) return;
1636 switch ((t_name&&(t_res==TR_VALUE))?TR_OMIT:t_res) {
1637 case TR_VALUE:
1638 if (!is_ifpresent && template_selection==SPECIFIC_VALUE) return;
1639 break;
1640 case TR_OMIT:
1641 if (!is_ifpresent && (template_selection==OMIT_VALUE ||
1642 template_selection==SPECIFIC_VALUE)) return;
1643 break;
1644 case TR_PRESENT:
3abe9331 1645 if (!match_omit(legacy)) return;
970ed795
EL
1646 break;
1647 default:
1648 return;
1649 }
1650 TTCN_error("Restriction `%s' on template of type %s violated.",
1651 get_res_name(t_res), t_name ? t_name : "float");
1652}
1653#endif
This page took 0.08351 seconds and 5 git commands to generate.