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
20 * Szabo, Janos Zoltan – initial implementation
24 ******************************************************************************/
29 #include "../common/memory.h"
32 #include "Param_Types.hh"
33 #include "Optional.hh"
39 #include "Charstring.hh"
41 #include "XmlReader.hh"
43 #include "../common/dbgnew.hh"
47 #define INFINITY (DBL_MAX*DBL_MAX)
49 const FLOAT
PLUS_INFINITY(INFINITY
);
50 const FLOAT
MINUS_INFINITY(-INFINITY
);
53 const FLOAT
NOT_A_NUMBER(NAN
);
55 const FLOAT
NOT_A_NUMBER((double)PLUS_INFINITY
+(double)MINUS_INFINITY
);
56 // The casts ensure that FLOAT::operator+ is not called
60 static inline void log_float(double float_val
)
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
);
82 FLOAT::FLOAT(double other_value
)
85 float_value
= other_value
;
88 FLOAT::FLOAT(const FLOAT
& other_value
)
89 : Base_Type(other_value
)
91 other_value
.must_bound("Copying an unbound float value.");
93 float_value
= other_value
.float_value
;
96 void FLOAT::clean_up()
101 FLOAT
& FLOAT::operator=(double other_value
)
104 float_value
= other_value
;
108 FLOAT
& FLOAT::operator=(const FLOAT
& other_value
)
110 other_value
.must_bound("Assignment of an unbound float value.");
112 float_value
= other_value
.float_value
;
116 double FLOAT::operator+() const
118 must_bound("Unbound float operand of unary + operator.");
122 double FLOAT::operator-() const
124 must_bound("Unbound float operand of unary - operator (negation).");
128 bool FLOAT::is_special(double flt_val
)
130 return ( (flt_val
!=flt_val
) || (flt_val
==INFINITY
) || (flt_val
==-INFINITY
) );
133 void FLOAT::check_numeric(double flt_val
, const char *err_msg_begin
)
135 if (is_special(flt_val
)) {
136 TTCN_error("%s must be a numeric value instead of %g",
137 err_msg_begin
, flt_val
);
141 double FLOAT::operator+(double other_value
) const
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
;
149 double FLOAT::operator+(const FLOAT
& other_value
) const
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
;
158 double FLOAT::operator-(double other_value
) const
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
;
166 double FLOAT::operator-(const FLOAT
& other_value
) const
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
;
175 double FLOAT::operator*(double other_value
) const
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
;
183 double FLOAT::operator*(const FLOAT
& other_value
) const
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
;
192 double FLOAT::operator/(double other_value
) const
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
;
201 double FLOAT::operator/(const FLOAT
& other_value
) const
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
;
211 boolean
FLOAT::operator==(double other_value
) const
213 must_bound("Unbound left operand of float comparison.");
214 return float_value
== other_value
;
217 boolean
FLOAT::operator==(const FLOAT
& other_value
) const
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
;
224 boolean
FLOAT::operator<(double other_value
) const
226 must_bound("Unbound left operand of float comparison.");
227 return float_value
< other_value
;
230 boolean
FLOAT::operator<(const FLOAT
& other_value
) const
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
;
237 boolean
FLOAT::operator>(double other_value
) const
239 must_bound("Unbound left operand of float comparison.");
240 return float_value
> other_value
;
243 boolean
FLOAT::operator>(const FLOAT
& other_value
) const
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
;
250 FLOAT::operator double() const
252 must_bound("Using the value of an unbound float variable.");
256 void FLOAT::log() const
258 if (bound_flag
) log_float(float_value
);
259 else TTCN_Logger::log_event_unbound();
262 void FLOAT::set_param(Module_Param
& param
) {
263 param
.basic_check(Module_Param::BC_VALUE
, "float value");
264 Module_Param_Ptr mp
= ¶m
;
265 if (param
.get_type() == Module_Param::MP_Reference
) {
266 mp
= param
.get_referenced_param();
268 switch (mp
->get_type()) {
269 case Module_Param::MP_Float
: {
272 float_value
= mp
->get_float();
274 case Module_Param::MP_Expression
:
275 switch (mp
->get_expr_type()) {
276 case Module_Param::EXPR_NEGATE
: {
278 operand
.set_param(*mp
->get_operand1());
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
;
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
;
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
;
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.");
306 *this = operand1
/ operand2
;
309 param
.expr_type_error("a float");
314 param
.type_error("float value");
319 Module_Param
* FLOAT::get_param(Module_Param_Name
& /* param_name */) const
322 return new Module_Param_Unbound();
324 return new Module_Param_Float(float_value
);
327 void FLOAT::encode_text(Text_Buf
& text_buf
) const
329 must_bound("Text encoder: Encoding an unbound float value.");
330 text_buf
.push_double(float_value
);
333 void FLOAT::decode_text(Text_Buf
& text_buf
)
336 float_value
= text_buf
.pull_double();
339 void FLOAT::encode(const TTCN_Typedescriptor_t
& p_td
, TTCN_Buffer
& p_buf
,
340 TTCN_EncDec::coding_t p_coding
, ...) const
343 va_start(pvar
, 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
);
353 case TTCN_EncDec::CT_RAW
: {
354 TTCN_EncDec_ErrorContext
ec("While RAW-encoding type '%s': ", p_td
.name
);
356 TTCN_EncDec_ErrorContext::error_internal
357 ("No RAW descriptor available for type '%s'.", p_td
.name
);
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
);
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);
368 XER_encode(*p_td
.xer
, p_buf
, XER_coding
, 0, 0);
370 case TTCN_EncDec::CT_JSON
: {
371 TTCN_EncDec_ErrorContext
ec("While JSON-encoding type '%s': ", p_td
.name
);
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());
380 TTCN_error("Unknown coding method requested to encode type '%s'",
386 void FLOAT::decode(const TTCN_Typedescriptor_t
& p_td
, TTCN_Buffer
& p_buf
,
387 TTCN_EncDec::coding_t p_coding
, ...)
390 va_start(pvar
, 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);
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());
400 case TTCN_EncDec::CT_RAW
: {
401 TTCN_EncDec_ErrorContext
ec("While RAW-decoding type '%s': ", p_td
.name
);
403 TTCN_EncDec_ErrorContext::error_internal
404 ("No RAW descriptor available for type '%s'.", p_td
.name
);
406 switch(p_td
.raw
->top_bit_order
){
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"
420 case TTCN_EncDec::CT_XER
: {
421 TTCN_EncDec_ErrorContext
ec("While XER-decoding type '%s': ", p_td
.name
);
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
)
429 XER_decode(*p_td
.xer
, reader
, XER_coding
, XER_NONE
, 0);
430 size_t bytes
= reader
.ByteConsumed();
431 p_buf
.set_pos(bytes
);
433 case TTCN_EncDec::CT_JSON
: {
434 TTCN_EncDec_ErrorContext
ec("While JSON-decoding type '%s': ", p_td
.name
);
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"
444 p_buf
.set_pos(tok
.get_buf_pos());
447 TTCN_error("Unknown coding method requested to decode type '%s'",
454 FLOAT::BER_encode_TLV(const TTCN_Typedescriptor_t
& p_td
,
455 unsigned p_coding
) const
458 ASN_BER_TLV_t
*new_tlv
=BER_encode_chk_bound(is_bound());
460 if(float_value
==0.0) {
461 new_tlv
=ASN_BER_TLV_t::construct();
462 // nothing to do, Vlen is 0
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;
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;
474 else if(isnan((double)float_value
)) {
475 TTCN_EncDec_ErrorContext::error_internal("Value is NaN.");
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;
486 warning: `.' not followed by `*' or digit in format
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]);
493 new_tlv
=ASN_BER_V2TLV(new_tlv
, p_td
, p_coding
);
497 boolean
FLOAT::BER_decode_TLV(const TTCN_Typedescriptor_t
& p_td
,
498 const ASN_BER_TLV_t
& p_tlv
,
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
;
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"
520 else if(Vstr
[0] & 0x40) {
521 /* SpecialRealValue */
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).");
527 ec
.error(TTCN_EncDec::ET_INVAL_MSG
,
528 "This is a reserved value: 0x%x (See X.690 8.5.8).",
532 float_value
=-INFINITY
;
535 float_value
=INFINITY
;
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).",
543 int NR
=Vstr
[0] & 0x03; // which NumericalRepresentation
548 *Vstr_last
=Vstr
+Vlen
-1,
562 if(Vlen
==1) goto dec_error
;
564 if(ptr
==Vstr_last
) goto dec_error
;
567 if(*ptr
=='+' || *ptr
=='-') {
569 if(ptr
==Vstr_last
) goto dec_error
;
574 if(ptr
==Vstr_last
) goto str_end
;
577 while(*ptr
>='0' && *ptr
<='9') {
578 if(mant1_len
==0) mant1
=ptr
;
580 if(ptr
==Vstr_last
) goto str_end
;
583 if(*ptr
=='.' || *ptr
==',') {
585 if(ptr
==Vstr_last
) goto str_end
;
588 while(*ptr
>='0' && *ptr
<='9') {
589 if(mant2_len
==0) mant2
=ptr
;
591 if(ptr
==Vstr_last
) goto str_end
;
594 if(!leadingzero
&& !mant1
&& !mant2
) goto dec_error
;
595 if(*ptr
=='e' || *ptr
=='E') {
597 if(ptr
==Vstr_last
) goto dec_error
;
600 if(*ptr
=='+' || *ptr
=='-') {
602 if(ptr
==Vstr_last
) goto dec_error
;
607 if(ptr
==Vstr_last
) goto str_end
;
610 while(*ptr
>='0' && *ptr
<='9') {
611 if(expo_len
==0) expo
=ptr
;
613 if(ptr
==Vstr_last
) goto str_end
;
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.");
623 if(decmark
|| expmark
) NR_error
=TRUE
;
626 if(expmark
) NR_error
=TRUE
;
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
;
634 if(mant1
) for(size_t i
=0; i
<mant1_len
; i
++) {
636 float_value
+=static_cast<double>(mant1
[i
]-'0');
638 if(mant2
) for(size_t i
=0; i
<mant2_len
; i
++) {
640 float_value
+=static_cast<double>(mant2
[i
]-'0');
644 if(ceil(log10(log10(DBL_MAX
)))<expo_len
) {
646 if(expsign
&& *expsign
=='-') {
650 if(sign
&& *sign
=='-') float_value
=-INFINITY
;
651 else float_value
=INFINITY
;
657 for(size_t i
=0; i
<expo_len
; i
++) {
659 exponum
+=static_cast<int>(expo
[i
]-'0');
661 if(expsign
&& *expsign
=='-')
665 if(mant2
) exponum
-=mant2_len
;
666 float_value
*=pow(10.0, static_cast<double>(exponum
));
669 ec
.error(TTCN_EncDec::ET_INVAL_MSG
, "Erroneous decimal encoding.");
677 int FLOAT::RAW_encode(const TTCN_Typedescriptor_t
& p_td
, RAW_enc_tree
& myleaf
) const
681 int length
= p_td
.raw
->fieldlength
/ 8;
682 double tmp
= float_value
;
684 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
685 "Encoding an unbound value.");
689 TTCN_EncDec_ErrorContext::error_internal("Value is NaN.");
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
;
698 bc
= myleaf
.body
.leaf
.data_array
;
701 dv
= (unsigned char *) &tmp
;
702 #if defined __sparc__ || defined __sparc
705 for (int i
= 0, k
= 7; i
< 8; i
++, k
--) bc
[i
] = dv
[k
];
708 else if (length
== 4) {
709 if (tmp
== 0.0) memset(bc
, 0, 4);
710 else if (tmp
== -0.0) {
715 #if defined __sparc__ || defined __sparc
722 dv
= (unsigned char *) &tmp
;
723 bc
[0] = dv
[index
] & 0x80;
724 int exponent
= dv
[index
] & 0x7F;
727 exponent
+= (dv
[index
] & 0xF0) >> 4;
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
);
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
);
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);
749 bc
[2] = ((dv
[index
] & 0x1F) << 3) | ((dv
[index
+ adj
] & 0xE0) >> 5);
751 bc
[3] = ((dv
[index
] & 0x1F) << 3) | ((dv
[index
+ adj
] & 0xE0) >> 5);
755 TTCN_EncDec_ErrorContext::error_internal("Invalid FLOAT length %d", length
);
757 return myleaf
.length
= p_td
.raw
->fieldlength
;
760 int 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*/)
764 int prepaddlength
= buff
.increase_pos_padd(p_td
.raw
->prepadding
);
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
;
777 decode_length
+= buff
.increase_pos_padd(p_td
.raw
->padding
);
778 return decode_length
+ prepaddlength
;
781 unsigned char data
[16];
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
;
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
799 for (int i
= 0, k
= 7; i
< 8; i
++, k
--) dv
[i
] = data
[k
];
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
);
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);
813 fraction
+= ((data
[2] & 0x7F) << 1) | ((data
[3] & 0x80) >> 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
);
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)
829 double sign_v
= sign
? -1.0 : 1.0;
831 tmp
= sign_v
* (1.0 + static_cast<double> (fraction
) / 8388608.0)
832 * pow(2.0, static_cast<double> (exponent
));
836 decode_length
+= buff
.increase_pos_padd(p_td
.raw
->padding
);
839 return decode_length
+ prepaddlength
;
842 int FLOAT::XER_encode(const XERdescriptor_t
& p_td
,
843 TTCN_Buffer
& p_buf
, unsigned int flavor
, int indent
, embed_values_enc_struct_t
*) const
846 TTCN_EncDec_ErrorContext::error(
847 TTCN_EncDec::ET_UNBOUND
, "Encoding an unbound float value.");
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
854 begin_xml(p_td
, p_buf
, flavor
, indent
, false);
856 if (exer
&& (p_td
.xer_bits
& XER_DECIMAL
)) {
858 int n
= snprintf(buf
, sizeof(buf
), "%f", (double)float_value
);
859 p_buf
.put_s((size_t)n
, (const unsigned char*)buf
);
862 CHARSTRING value
= float2str(float_value
);
863 p_buf
.put_string(value
);
866 end_xml(p_td
, p_buf
, flavor
, indent
, false);
868 return (int)p_buf
.get_len() - encoded_length
;
871 boolean
FLOAT::is_float(const char* p_str
)
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
878 if ('-' == *p_str
|| '+' == *p_str
) {
882 while (0 != *p_str
) {
885 if (decimal_point
|| exponent_mark
|| !first_digit
) {
888 decimal_point
= true;
893 if (exponent_mark
|| !first_digit
) {
896 exponent_mark
= true;
913 if (exponent_sign
|| !exponent_mark
|| first_digit
) {
916 exponent_sign
= true;
927 int FLOAT::XER_decode(const XERdescriptor_t
& p_td
, XmlReaderWrap
& reader
,
928 unsigned int flavor
, unsigned int /*flavor2*/, embed_values_dec_struct_t
*)
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
);
936 if (!own_tag
) goto tagless
;
937 if (exer
&& (p_td
.xer_bits
& XER_ATTRIBUTE
)) {
938 verify_name(reader
, p_td
, exer
);
940 const char * value
= (const char *)reader
.Value();
942 if (value
&& is_float(value
)) {
944 sscanf(value
, "%lf", &float_value
);
947 // Let the caller do reader.AdvanceAttribute();
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
);
961 depth
= reader
.Depth();
963 else if (XML_READER_TYPE_TEXT
== type
&& depth
!= -1) {
964 const char * value
= (const char*)reader
.Value();
965 if (value
&& is_float(value
)) {
967 sscanf(value
, "%lf", &float_value
);
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
);
979 } // if not attribute
980 return 1; // decode successful
983 const char* POS_INF_STR
= "\"infinity\"";
984 const char* NEG_INF_STR
= "\"-infinity\"";
985 const char* NAN_STR
= "\"not_a_number\"";
987 int FLOAT::JSON_encode(const TTCN_Typedescriptor_t
&, JSON_Tokenizer
& p_tok
) const
990 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
991 "Encoding an unbound float value.");
995 double value
= (double)float_value
;
996 if ((double)INFINITY
== value
) {
997 return p_tok
.put_next_token(JSON_TOKEN_STRING
, POS_INF_STR
);
999 if (-(double)INFINITY
== value
) {
1000 return p_tok
.put_next_token(JSON_TOKEN_STRING
, NEG_INF_STR
);
1003 return p_tok
.put_next_token(JSON_TOKEN_STRING
, NAN_STR
);
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
);
1011 char* tmp_str
= mprintf(decimal_repr
? "%f" : "%e", value
);
1012 int enc_len
= p_tok
.put_next_token(JSON_TOKEN_NUMBER
, tmp_str
);
1017 int FLOAT::JSON_decode(const TTCN_Typedescriptor_t
& p_td
, JSON_Tokenizer
& p_tok
, boolean p_silent
)
1020 json_token_t token
= JSON_TOKEN_NONE
;
1022 size_t value_len
= 0;
1024 boolean use_default
= p_td
.json
->default_value
&& 0 == p_tok
.get_buffer_length();
1026 // No JSON data in the buffer -> use default value
1027 value
= (char*)p_td
.json
->default_value
;
1028 value_len
= strlen(value
);
1030 dec_len
= p_tok
.get_next_token(&token
, &value
, &value_len
);
1032 if (JSON_TOKEN_ERROR
== token
) {
1033 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG
, JSON_DEC_BAD_TOKEN_ERROR
, "");
1034 return JSON_ERROR_FATAL
;
1036 else if (JSON_TOKEN_STRING
== token
|| use_default
) {
1037 if (0 == strncmp(value
, POS_INF_STR
+ (use_default
? 1 : 0), value_len
)) {
1039 float_value
= INFINITY
;
1041 else if (0 == strncmp(value
, NEG_INF_STR
+ (use_default
? 1 : 0), value_len
)) {
1043 float_value
= -INFINITY
;
1045 else if (0 == strncmp(value
, NAN_STR
+ (use_default
? 1 : 0), value_len
)) {
1050 float_value
= INFINITY
+ (-INFINITY
);
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
);
1058 return JSON_ERROR_FATAL
;
1061 else if (JSON_TOKEN_NUMBER
== token
) {
1062 char* value2
= mcopystrn(value
, value_len
);
1063 sscanf(value2
, "%lf", &float_value
);
1067 return JSON_ERROR_INVALID_TOKEN
;
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
);
1083 double operator+(double double_value
, const FLOAT
& other_value
)
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
;
1091 double operator-(double double_value
, const FLOAT
& other_value
)
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
;
1099 double operator*(double double_value
, const FLOAT
& other_value
)
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
;
1107 double operator/(double double_value
, const FLOAT
& other_value
)
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
;
1116 boolean
operator==(double double_value
, const FLOAT
& other_value
)
1118 other_value
.must_bound("Unbound right operand of float comparison.");
1119 return double_value
== other_value
.float_value
;
1122 boolean
operator<(double double_value
, const FLOAT
& other_value
)
1124 other_value
.must_bound("Unbound right operand of float comparison.");
1125 return double_value
< other_value
.float_value
;
1128 boolean
operator>(double double_value
, const FLOAT
& other_value
)
1130 other_value
.must_bound("Unbound right operand of float comparison.");
1131 return double_value
> other_value
.float_value
;
1134 // float template class
1136 void FLOAT_template::clean_up()
1138 if (template_selection
== VALUE_LIST
||
1139 template_selection
== COMPLEMENTED_LIST
)
1140 delete [] value_list
.list_value
;
1141 template_selection
= UNINITIALIZED_TEMPLATE
;
1144 void FLOAT_template::copy_template(const FLOAT_template
& other_value
)
1146 switch (other_value
.template_selection
) {
1147 case SPECIFIC_VALUE
:
1148 single_value
= other_value
.single_value
;
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
]);
1163 value_range
= other_value
.value_range
;
1166 TTCN_error("Copying an uninitialized/unsupported float template.");
1168 set_selection(other_value
);
1171 FLOAT_template::FLOAT_template()
1176 FLOAT_template::FLOAT_template(template_sel other_value
)
1177 : Base_Template(other_value
)
1179 check_single_selection(other_value
);
1182 FLOAT_template::FLOAT_template(double other_value
)
1183 : Base_Template(SPECIFIC_VALUE
)
1185 single_value
= other_value
;
1188 FLOAT_template::FLOAT_template(const FLOAT
& other_value
)
1189 : Base_Template(SPECIFIC_VALUE
)
1191 other_value
.must_bound("Creating a template from an unbound float value.");
1192 single_value
= other_value
.float_value
;
1195 FLOAT_template::FLOAT_template(const OPTIONAL
<FLOAT
>& other_value
)
1197 switch (other_value
.get_selection()) {
1198 case OPTIONAL_PRESENT
:
1199 set_selection(SPECIFIC_VALUE
);
1200 single_value
= (double)(const FLOAT
&)other_value
;
1203 set_selection(OMIT_VALUE
);
1206 TTCN_error("Creating a float template from an unbound optional field.");
1210 FLOAT_template::FLOAT_template(const FLOAT_template
& other_value
)
1213 copy_template(other_value
);
1216 FLOAT_template::~FLOAT_template()
1221 FLOAT_template
& FLOAT_template::operator=(template_sel other_value
)
1223 check_single_selection(other_value
);
1225 set_selection(other_value
);
1229 FLOAT_template
& FLOAT_template::operator=(double other_value
)
1232 set_selection(SPECIFIC_VALUE
);
1233 single_value
= other_value
;
1237 FLOAT_template
& FLOAT_template::operator=(const FLOAT
& other_value
)
1239 other_value
.must_bound("Assignment of an unbound float value "
1242 set_selection(SPECIFIC_VALUE
);
1243 single_value
= other_value
.float_value
;
1247 FLOAT_template
& FLOAT_template::operator=(const OPTIONAL
<FLOAT
>& other_value
)
1250 switch (other_value
.get_selection()) {
1251 case OPTIONAL_PRESENT
:
1252 set_selection(SPECIFIC_VALUE
);
1253 single_value
= (double)(const FLOAT
&)other_value
;
1256 set_selection(OMIT_VALUE
);
1259 TTCN_error("Assignment of an unbound optional field to a float template.");
1264 FLOAT_template
& FLOAT_template::operator=(const FLOAT_template
& other_value
)
1266 if (&other_value
!= this) {
1268 copy_template(other_value
);
1273 boolean
FLOAT_template::match(double other_value
, boolean
/* legacy */) const
1275 switch (template_selection
) {
1276 case SPECIFIC_VALUE
:
1277 return single_value
== other_value
|| // check if they're both NaN
1278 (single_value
!= single_value
&& other_value
!= other_value
);
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
;
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
);
1296 TTCN_error("Matching with an uninitialized/unsupported float template.");
1301 boolean
FLOAT_template::match(const FLOAT
& other_value
, boolean
/* legacy */) const
1303 if (!other_value
.is_bound()) return FALSE
;
1304 return match(other_value
.float_value
);
1308 void FLOAT_template::set_type(template_sel template_type
,
1309 unsigned int list_length
)
1312 switch (template_type
) {
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
];
1320 set_selection(VALUE_RANGE
);
1321 value_range
.min_is_present
= FALSE
;
1322 value_range
.max_is_present
= FALSE
;
1325 TTCN_error("Setting an invalid type for a float template.");
1329 FLOAT_template
& FLOAT_template::list_item(unsigned int list_index
)
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
];
1339 void FLOAT_template::set_min(double min_value
)
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
;
1350 void FLOAT_template::set_min(const FLOAT
& min_value
)
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
);
1357 void FLOAT_template::set_max(double max_value
)
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
;
1368 void FLOAT_template::set_max(const FLOAT
& max_value
)
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
);
1375 double FLOAT_template::valueof() const
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
;
1383 void FLOAT_template::log() const
1385 switch (template_selection
) {
1386 case SPECIFIC_VALUE
:
1387 log_float(single_value
);
1389 case COMPLEMENTED_LIST
:
1390 TTCN_Logger::log_event_str("complement ");
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();
1398 TTCN_Logger::log_char(')');
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(')');
1416 void FLOAT_template::log_match(const FLOAT
& match_value
,
1417 boolean
/* legacy */) const
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(" := ");
1425 TTCN_Logger::log_event_str(" with ");
1427 if (match(match_value
)) TTCN_Logger::log_event_str(" matched");
1428 else TTCN_Logger::log_event_str(" unmatched");
1431 void FLOAT_template::set_param(Module_Param
& param
) {
1432 param
.basic_check(Module_Param::BC_TEMPLATE
, "float template");
1433 Module_Param_Ptr mp
= ¶m
;
1434 if (param
.get_type() == Module_Param::MP_Reference
) {
1435 mp
= param
.get_referenced_param();
1437 switch (mp
->get_type()) {
1438 case Module_Param::MP_Omit
:
1441 case Module_Param::MP_Any
:
1444 case Module_Param::MP_AnyOrNone
:
1445 *this = ANY_OR_OMIT
;
1447 case Module_Param::MP_List_Template
:
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
));
1457 case Module_Param::MP_Float
:
1458 *this = mp
->get_float();
1460 case Module_Param::MP_FloatRange
:
1461 set_type(VALUE_RANGE
);
1462 if (mp
->has_lower_float()) set_min(mp
->get_lower_float());
1463 if (mp
->has_upper_float()) set_max(mp
->get_upper_float());
1465 case Module_Param::MP_Expression
:
1466 switch (mp
->get_expr_type()) {
1467 case Module_Param::EXPR_NEGATE
: {
1469 operand
.set_param(*mp
->get_operand1());
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
;
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
;
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
;
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.");
1497 *this = operand1
/ operand2
;
1500 param
.expr_type_error("a float");
1505 param
.type_error("float template");
1507 is_ifpresent
= param
.get_ifpresent() || mp
->get_ifpresent();
1510 Module_Param
* FLOAT_template::get_param(Module_Param_Name
& param_name
) const
1512 Module_Param
* mp
= NULL
;
1513 switch (template_selection
) {
1514 case UNINITIALIZED_TEMPLATE
:
1515 mp
= new Module_Param_Unbound();
1518 mp
= new Module_Param_Omit();
1521 mp
= new Module_Param_Any();
1524 mp
= new Module_Param_AnyOrNone();
1526 case SPECIFIC_VALUE
:
1527 mp
= new Module_Param_Float(single_value
);
1530 case COMPLEMENTED_LIST
: {
1531 if (template_selection
== VALUE_LIST
) {
1532 mp
= new Module_Param_List_Template();
1535 mp
= new Module_Param_ComplementList_Template();
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
));
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
);
1550 mp
->set_ifpresent();
1555 void FLOAT_template::encode_text(Text_Buf
& text_buf
) const
1557 encode_text_base(text_buf
);
1558 switch (template_selection
) {
1563 case SPECIFIC_VALUE
:
1564 text_buf
.push_double(single_value
);
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
);
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
);
1581 TTCN_error("Text encoder: Encoding an undefined/unsupported "
1586 void FLOAT_template::decode_text(Text_Buf
& text_buf
)
1589 decode_text_base(text_buf
);
1590 switch (template_selection
) {
1595 case SPECIFIC_VALUE
:
1596 single_value
= text_buf
.pull_double();
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
);
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();
1614 TTCN_error("Text decoder: An unknown/unsupported selection was "
1615 "received for a float template.");
1619 boolean
FLOAT_template::is_present(boolean legacy
/* = FALSE */) const
1621 if (template_selection
==UNINITIALIZED_TEMPLATE
) return FALSE
;
1622 return !match_omit(legacy
);
1625 boolean
FLOAT_template::match_omit(boolean legacy
/* = FALSE */) const
1627 if (is_ifpresent
) return TRUE
;
1628 switch (template_selection
) {
1633 case COMPLEMENTED_LIST
:
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
;
1641 // else fall through
1648 #ifndef TITAN_RUNTIME_2
1649 void FLOAT_template::check_restriction(template_res t_res
, const char* t_name
,
1650 boolean legacy
/* = FALSE */) const
1652 if (template_selection
==UNINITIALIZED_TEMPLATE
) return;
1653 switch ((t_name
&&(t_res
==TR_VALUE
))?TR_OMIT
:t_res
) {
1655 if (!is_ifpresent
&& template_selection
==SPECIFIC_VALUE
) return;
1658 if (!is_ifpresent
&& (template_selection
==OMIT_VALUE
||
1659 template_selection
==SPECIFIC_VALUE
)) return;
1662 if (!match_omit(legacy
)) return;
1667 TTCN_error("Restriction `%s' on template of type %s violated.",
1668 get_res_name(t_res
), t_name
? t_name
: "float");