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