1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 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 ///////////////////////////////////////////////////////////////////////////////
12 #include "../common/memory.h"
15 #include "Param_Types.hh"
16 #include "Optional.hh"
22 #include "Charstring.hh"
24 #include "XmlReader.hh"
26 #include "../common/dbgnew.hh"
30 #define INFINITY (DBL_MAX*DBL_MAX)
32 const FLOAT
PLUS_INFINITY(INFINITY
);
33 const FLOAT
MINUS_INFINITY(-INFINITY
);
36 const FLOAT
NOT_A_NUMBER(NAN
);
38 const FLOAT
NOT_A_NUMBER((double)PLUS_INFINITY
+(double)MINUS_INFINITY
);
39 // The casts ensure that FLOAT::operator+ is not called
43 static inline void log_float(double float_val
)
45 if ( (float_val
> -MAX_DECIMAL_FLOAT
&& float_val
<= -MIN_DECIMAL_FLOAT
)
46 || (float_val
>= MIN_DECIMAL_FLOAT
&& float_val
< MAX_DECIMAL_FLOAT
)
47 || (float_val
== 0.0))
48 TTCN_Logger::log_event("%f", float_val
);
49 else if(float_val
==INFINITY
)
50 TTCN_Logger::log_event_str("infinity");
51 else if(float_val
==-INFINITY
)
52 TTCN_Logger::log_event_str("-infinity");
53 else if(float_val
!=float_val
)
54 TTCN_Logger::log_event_str("not_a_number");
55 else TTCN_Logger::log_event("%e", float_val
);
65 FLOAT::FLOAT(double other_value
)
68 float_value
= other_value
;
71 FLOAT::FLOAT(const FLOAT
& other_value
)
72 : Base_Type(other_value
)
74 other_value
.must_bound("Copying an unbound float value.");
76 float_value
= other_value
.float_value
;
79 void FLOAT::clean_up()
84 FLOAT
& FLOAT::operator=(double other_value
)
87 float_value
= other_value
;
91 FLOAT
& FLOAT::operator=(const FLOAT
& other_value
)
93 other_value
.must_bound("Assignment of an unbound float value.");
95 float_value
= other_value
.float_value
;
99 double FLOAT::operator+() const
101 must_bound("Unbound float operand of unary + operator.");
105 double FLOAT::operator-() const
107 must_bound("Unbound float operand of unary - operator (negation).");
111 bool FLOAT::is_special(double flt_val
)
113 return ( (flt_val
!=flt_val
) || (flt_val
==INFINITY
) || (flt_val
==-INFINITY
) );
116 void FLOAT::check_numeric(double flt_val
, const char *err_msg_begin
)
118 if (is_special(flt_val
)) {
119 TTCN_error("%s must be a numeric value instead of %g",
120 err_msg_begin
, flt_val
);
124 double FLOAT::operator+(double other_value
) const
126 must_bound("Unbound left operand of float addition.");
127 check_numeric(float_value
, "Left operand of float addition");
128 check_numeric(other_value
, "Right operand of float addition");
129 return float_value
+ other_value
;
132 double FLOAT::operator+(const FLOAT
& other_value
) const
134 must_bound("Unbound left operand of float addition.");
135 other_value
.must_bound("Unbound right operand of float addition.");
136 check_numeric(float_value
, "Left operand of float addition");
137 check_numeric(other_value
.float_value
, "Right operand of float addition");
138 return float_value
+ other_value
.float_value
;
141 double FLOAT::operator-(double other_value
) const
143 must_bound("Unbound left operand of float subtraction.");
144 check_numeric(float_value
, "Left operand of float subtraction");
145 check_numeric(other_value
, "Right operand of float subtraction");
146 return float_value
- other_value
;
149 double FLOAT::operator-(const FLOAT
& other_value
) const
151 must_bound("Unbound left operand of float subtraction.");
152 other_value
.must_bound("Unbound right operand of float subtraction.");
153 check_numeric(float_value
, "Left operand of float subtraction");
154 check_numeric(other_value
.float_value
, "Right operand of float subtraction");
155 return float_value
- other_value
.float_value
;
158 double FLOAT::operator*(double other_value
) const
160 must_bound("Unbound left operand of float multiplication.");
161 check_numeric(float_value
, "Left operand of float multiplication");
162 check_numeric(other_value
, "Right operand of float multiplication");
163 return float_value
* other_value
;
166 double FLOAT::operator*(const FLOAT
& other_value
) const
168 must_bound("Unbound left operand of float multiplication.");
169 other_value
.must_bound("Unbound right operand of float multiplication.");
170 check_numeric(float_value
, "Left operand of float multiplication");
171 check_numeric(other_value
.float_value
, "Right operand of float multiplication");
172 return float_value
* other_value
.float_value
;
175 double FLOAT::operator/(double other_value
) const
177 must_bound("Unbound left operand of float division.");
178 check_numeric(float_value
, "Left operand of float division");
179 check_numeric(other_value
, "Right operand of float division");
180 if (other_value
== 0.0) TTCN_error("Float division by zero.");
181 return float_value
/ other_value
;
184 double FLOAT::operator/(const FLOAT
& other_value
) const
186 must_bound("Unbound left operand of float division.");
187 other_value
.must_bound("Unbound right operand of float division.");
188 check_numeric(float_value
, "Left operand of float division");
189 check_numeric(other_value
.float_value
, "Right operand of float division");
190 if (other_value
.float_value
== 0.0) TTCN_error("Float division by zero.");
191 return float_value
/ other_value
.float_value
;
194 boolean
FLOAT::operator==(double other_value
) const
196 must_bound("Unbound left operand of float comparison.");
197 return float_value
== other_value
;
200 boolean
FLOAT::operator==(const FLOAT
& other_value
) const
202 must_bound("Unbound left operand of float comparison.");
203 other_value
.must_bound("Unbound right operand of float comparison.");
204 return float_value
== other_value
.float_value
;
207 boolean
FLOAT::operator<(double other_value
) const
209 must_bound("Unbound left operand of float comparison.");
210 return float_value
< other_value
;
213 boolean
FLOAT::operator<(const FLOAT
& other_value
) const
215 must_bound("Unbound left operand of float comparison.");
216 other_value
.must_bound("Unbound right operand of float comparison.");
217 return float_value
< other_value
.float_value
;
220 boolean
FLOAT::operator>(double other_value
) const
222 must_bound("Unbound left operand of float comparison.");
223 return float_value
> other_value
;
226 boolean
FLOAT::operator>(const FLOAT
& other_value
) const
228 must_bound("Unbound left operand of float comparison.");
229 other_value
.must_bound("Unbound right operand of float comparison.");
230 return float_value
> other_value
.float_value
;
233 FLOAT::operator double() const
235 must_bound("Using the value of an unbound float variable.");
239 void FLOAT::log() const
241 if (bound_flag
) log_float(float_value
);
242 else TTCN_Logger::log_event_unbound();
245 void FLOAT::set_param(Module_Param
& param
) {
246 param
.basic_check(Module_Param::BC_VALUE
, "float value");
247 Module_Param_Ptr mp
= ¶m
;
248 if (param
.get_type() == Module_Param::MP_Reference
) {
249 mp
= param
.get_referenced_param();
251 switch (mp
->get_type()) {
252 case Module_Param::MP_Float
: {
255 float_value
= mp
->get_float();
257 case Module_Param::MP_Expression
:
258 switch (mp
->get_expr_type()) {
259 case Module_Param::EXPR_NEGATE
: {
261 operand
.set_param(*mp
->get_operand1());
264 case Module_Param::EXPR_ADD
: {
265 FLOAT operand1
, operand2
;
266 operand1
.set_param(*mp
->get_operand1());
267 operand2
.set_param(*mp
->get_operand2());
268 *this = operand1
+ operand2
;
270 case Module_Param::EXPR_SUBTRACT
: {
271 FLOAT operand1
, operand2
;
272 operand1
.set_param(*mp
->get_operand1());
273 operand2
.set_param(*mp
->get_operand2());
274 *this = operand1
- operand2
;
276 case Module_Param::EXPR_MULTIPLY
: {
277 FLOAT operand1
, operand2
;
278 operand1
.set_param(*mp
->get_operand1());
279 operand2
.set_param(*mp
->get_operand2());
280 *this = operand1
* operand2
;
282 case Module_Param::EXPR_DIVIDE
: {
283 FLOAT operand1
, operand2
;
284 operand1
.set_param(*mp
->get_operand1());
285 operand2
.set_param(*mp
->get_operand2());
286 if (operand2
== 0.0) {
287 param
.error("Floating point division by zero.");
289 *this = operand1
/ operand2
;
292 param
.expr_type_error("a float");
297 param
.type_error("float value");
302 Module_Param
* FLOAT::get_param(Module_Param_Name
& /* param_name */) const
305 return new Module_Param_Unbound();
307 return new Module_Param_Float(float_value
);
310 void FLOAT::encode_text(Text_Buf
& text_buf
) const
312 must_bound("Text encoder: Encoding an unbound float value.");
313 text_buf
.push_double(float_value
);
316 void FLOAT::decode_text(Text_Buf
& text_buf
)
319 float_value
= text_buf
.pull_double();
322 void FLOAT::encode(const TTCN_Typedescriptor_t
& p_td
, TTCN_Buffer
& p_buf
,
323 TTCN_EncDec::coding_t p_coding
, ...) const
326 va_start(pvar
, p_coding
);
328 case TTCN_EncDec::CT_BER
: {
329 TTCN_EncDec_ErrorContext
ec("While BER-encoding type '%s': ", p_td
.name
);
330 unsigned BER_coding
=va_arg(pvar
, unsigned);
331 BER_encode_chk_coding(BER_coding
);
332 ASN_BER_TLV_t
*tlv
=BER_encode_TLV(p_td
, BER_coding
);
333 tlv
->put_in_buffer(p_buf
);
334 ASN_BER_TLV_t::destruct(tlv
);
336 case TTCN_EncDec::CT_RAW
: {
337 TTCN_EncDec_ErrorContext
ec("While RAW-encoding type '%s': ", p_td
.name
);
339 TTCN_EncDec_ErrorContext::error_internal
340 ("No RAW descriptor available for type '%s'.", p_td
.name
);
344 RAW_enc_tree
root(TRUE
,NULL
,&rp
,1,p_td
.raw
);
345 RAW_encode(p_td
, root
);
346 root
.put_to_buf(p_buf
);
348 case TTCN_EncDec::CT_XER
: {
349 TTCN_EncDec_ErrorContext
ec("While XER-encoding type '%s': ", p_td
.name
);
350 unsigned XER_coding
=va_arg(pvar
, unsigned);
351 XER_encode(*p_td
.xer
, p_buf
, XER_coding
, 0, 0);
353 case TTCN_EncDec::CT_JSON
: {
354 TTCN_EncDec_ErrorContext
ec("While JSON-encoding type '%s': ", p_td
.name
);
356 TTCN_EncDec_ErrorContext::error_internal
357 ("No JSON descriptor available for type '%s'.", p_td
.name
);
358 JSON_Tokenizer
tok(va_arg(pvar
, int) != 0);
359 JSON_encode(p_td
, tok
);
360 p_buf
.put_s(tok
.get_buffer_length(), (const unsigned char*)tok
.get_buffer());
363 TTCN_error("Unknown coding method requested to encode type '%s'",
369 void FLOAT::decode(const TTCN_Typedescriptor_t
& p_td
, TTCN_Buffer
& p_buf
,
370 TTCN_EncDec::coding_t p_coding
, ...)
373 va_start(pvar
, p_coding
);
375 case TTCN_EncDec::CT_BER
: {
376 TTCN_EncDec_ErrorContext
ec("While BER-decoding type '%s': ", p_td
.name
);
377 unsigned L_form
=va_arg(pvar
, unsigned);
379 BER_decode_str2TLV(p_buf
, tlv
, L_form
);
380 BER_decode_TLV(p_td
, tlv
, L_form
);
381 if(tlv
.isComplete
) p_buf
.increase_pos(tlv
.get_len());
383 case TTCN_EncDec::CT_RAW
: {
384 TTCN_EncDec_ErrorContext
ec("While RAW-decoding type '%s': ", p_td
.name
);
386 TTCN_EncDec_ErrorContext::error_internal
387 ("No RAW descriptor available for type '%s'.", p_td
.name
);
389 switch(p_td
.raw
->top_bit_order
){
397 if(RAW_decode(p_td
, p_buf
, p_buf
.get_len()*8, order
)<0)
398 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
399 "Can not decode type '%s', because invalid or incomplete"
400 " message was received"
403 case TTCN_EncDec::CT_XER
: {
404 TTCN_EncDec_ErrorContext
ec("While XER-decoding type '%s': ", p_td
.name
);
405 unsigned XER_coding
=va_arg(pvar
, unsigned);
406 XmlReaderWrap
reader(p_buf
);
407 for (int success
= reader
.Read(); success
==1; success
=reader
.Read()) {
408 int type
= reader
.NodeType();
409 if (type
==XML_READER_TYPE_ELEMENT
)
412 XER_decode(*p_td
.xer
, reader
, XER_coding
, XER_NONE
, 0);
413 size_t bytes
= reader
.ByteConsumed();
414 p_buf
.set_pos(bytes
);
416 case TTCN_EncDec::CT_JSON
: {
417 TTCN_EncDec_ErrorContext
ec("While JSON-decoding type '%s': ", p_td
.name
);
419 TTCN_EncDec_ErrorContext::error_internal
420 ("No JSON descriptor available for type '%s'.", p_td
.name
);
421 JSON_Tokenizer
tok((const char*)p_buf
.get_data(), p_buf
.get_len());
422 if(JSON_decode(p_td
, tok
, false)<0)
423 ec
.error(TTCN_EncDec::ET_INCOMPL_MSG
,
424 "Can not decode type '%s', because invalid or incomplete"
425 " message was received"
427 p_buf
.set_pos(tok
.get_buf_pos());
430 TTCN_error("Unknown coding method requested to decode type '%s'",
437 FLOAT::BER_encode_TLV(const TTCN_Typedescriptor_t
& p_td
,
438 unsigned p_coding
) const
441 ASN_BER_TLV_t
*new_tlv
=BER_encode_chk_bound(is_bound());
443 if(float_value
==0.0) {
444 new_tlv
=ASN_BER_TLV_t::construct();
445 // nothing to do, Vlen is 0
448 else if(float_value
==(double)INFINITY
) { // INFINITY may be float => cast
449 new_tlv
=ASN_BER_TLV_t::construct(1, NULL
);
450 new_tlv
->V
.str
.Vstr
[0]=0x40;
453 else if(float_value
==-(double)INFINITY
) {
454 new_tlv
=ASN_BER_TLV_t::construct(1, NULL
);
455 new_tlv
->V
.str
.Vstr
[0]=0x41;
457 else if(isnan((double)float_value
)) {
458 TTCN_EncDec_ErrorContext::error_internal("Value is NaN.");
461 new_tlv
=ASN_BER_TLV_t::construct();
462 double mantissa
, exponent
;
463 exponent
=floor(log10(fabs(float_value
)))+1.0-DBL_DIG
;
464 mantissa
=floor(float_value
*pow(10.0,-exponent
)+0.5);
465 if(mantissa
)while(!fmod(mantissa
,10.0))mantissa
/=10.0,exponent
+=1.0;
469 warning: `.' not followed by `*' or digit in format
471 new_tlv
->V
.str
.Vstr
=(unsigned char*)
472 mprintf("\x03%.f.E%s%.0f", mantissa
, exponent
==0.0?"+":"", exponent
);
473 new_tlv
->V
.str
.Vlen
=1+strlen((const char*)&new_tlv
->V
.str
.Vstr
[1]);
476 new_tlv
=ASN_BER_V2TLV(new_tlv
, p_td
, p_coding
);
480 boolean
FLOAT::BER_decode_TLV(const TTCN_Typedescriptor_t
& p_td
,
481 const ASN_BER_TLV_t
& p_tlv
,
486 ASN_BER_TLV_t stripped_tlv
;
487 BER_decode_strip_tags(*p_td
.ber
, p_tlv
, L_form
, stripped_tlv
);
488 TTCN_EncDec_ErrorContext
ec("While decoding REAL type: ");
489 stripped_tlv
.chk_constructed_flag(FALSE
);
490 if (!stripped_tlv
.isComplete
) return FALSE
;
491 size_t Vlen
=stripped_tlv
.V
.str
.Vlen
;
492 unsigned char *Vstr
=stripped_tlv
.V
.str
.Vstr
;
496 else if(Vstr
[0] & 0x80) {
497 /* binary encoding */
498 /** \todo Perhaps it were good to implement this. Perhaps not. :) */
499 ec
.warning("Sorry, decoding of binary encoded REAL values not"
503 else if(Vstr
[0] & 0x40) {
504 /* SpecialRealValue */
506 ec
.error(TTCN_EncDec::ET_INVAL_MSG
,
507 "In case of SpecialRealValue, the length of V-part must be 1"
508 " (See X.690 8.5.8).");
510 ec
.error(TTCN_EncDec::ET_INVAL_MSG
,
511 "This is a reserved value: 0x%x (See X.690 8.5.8).",
515 float_value
=-INFINITY
;
518 float_value
=INFINITY
;
521 /* decimal encoding */
522 if((Vstr
[0] & 0x3C) || (Vstr
[0] & 0x3F) == 0x00 )
523 ec
.error(TTCN_EncDec::ET_INVAL_MSG
,
524 "This is a reserved value: 0x%x (See X.690 8.5.7).",
526 int NR
=Vstr
[0] & 0x03; // which NumericalRepresentation
531 *Vstr_last
=Vstr
+Vlen
-1,
545 if(Vlen
==1) goto dec_error
;
547 if(ptr
==Vstr_last
) goto dec_error
;
550 if(*ptr
=='+' || *ptr
=='-') {
552 if(ptr
==Vstr_last
) goto dec_error
;
557 if(ptr
==Vstr_last
) goto str_end
;
560 while(*ptr
>='0' && *ptr
<='9') {
561 if(mant1_len
==0) mant1
=ptr
;
563 if(ptr
==Vstr_last
) goto str_end
;
566 if(*ptr
=='.' || *ptr
==',') {
568 if(ptr
==Vstr_last
) goto str_end
;
571 while(*ptr
>='0' && *ptr
<='9') {
572 if(mant2_len
==0) mant2
=ptr
;
574 if(ptr
==Vstr_last
) goto str_end
;
577 if(!leadingzero
&& !mant1
&& !mant2
) goto dec_error
;
578 if(*ptr
=='e' || *ptr
=='E') {
580 if(ptr
==Vstr_last
) goto dec_error
;
583 if(*ptr
=='+' || *ptr
=='-') {
585 if(ptr
==Vstr_last
) goto dec_error
;
590 if(ptr
==Vstr_last
) goto str_end
;
593 while(*ptr
>='0' && *ptr
<='9') {
594 if(expo_len
==0) expo
=ptr
;
596 if(ptr
==Vstr_last
) goto str_end
;
599 if(expo_len
==0 && expo
!=NULL
) expo_len
=1; /* only leading zero */
600 if(expsign
&& !expo
) goto dec_error
;
601 ec
.error(TTCN_EncDec::ET_INVAL_MSG
,
602 "Superfluous part at the end of decimal encoding.");
606 if(decmark
|| expmark
) NR_error
=TRUE
;
609 if(expmark
) NR_error
=TRUE
;
612 ec
.error(TTCN_EncDec::ET_INVAL_MSG
,
613 "This decimal encoding does not conform to NR%d form.", NR
);
614 while(mant2_len
>1 && mant2
[mant2_len
-1]=='0') mant2_len
--;
615 if(mant2_len
==1 && *mant2
=='0') mant2_len
=0, mant2
=NULL
;
617 if(mant1
) for(size_t i
=0; i
<mant1_len
; i
++) {
619 float_value
+=static_cast<double>(mant1
[i
]-'0');
621 if(mant2
) for(size_t i
=0; i
<mant2_len
; i
++) {
623 float_value
+=static_cast<double>(mant2
[i
]-'0');
627 if(ceil(log10(log10(DBL_MAX
)))<expo_len
) {
629 if(expsign
&& *expsign
=='-') {
633 if(sign
&& *sign
=='-') float_value
=-INFINITY
;
634 else float_value
=INFINITY
;
640 for(size_t i
=0; i
<expo_len
; i
++) {
642 exponum
+=static_cast<int>(expo
[i
]-'0');
644 if(expsign
&& *expsign
=='-')
648 if(mant2
) exponum
-=mant2_len
;
649 float_value
*=pow(10.0, static_cast<double>(exponum
));
652 ec
.error(TTCN_EncDec::ET_INVAL_MSG
, "Erroneous decimal encoding.");
660 int FLOAT::RAW_encode(const TTCN_Typedescriptor_t
& p_td
, RAW_enc_tree
& myleaf
) const
664 int length
= p_td
.raw
->fieldlength
/ 8;
665 double tmp
= float_value
;
667 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
668 "Encoding an unbound value.");
672 TTCN_EncDec_ErrorContext::error_internal("Value is NaN.");
674 if (myleaf
.must_free
) Free(myleaf
.body
.leaf
.data_ptr
);
675 if (length
> RAW_INT_ENC_LENGTH
) {
676 myleaf
.body
.leaf
.data_ptr
= bc
= (unsigned char*)Malloc(length
*sizeof(*bc
));
677 myleaf
.must_free
= TRUE
;
678 myleaf
.data_ptr_used
= TRUE
;
681 bc
= myleaf
.body
.leaf
.data_array
;
684 dv
= (unsigned char *) &tmp
;
685 #if defined __sparc__ || defined __sparc
688 for (int i
= 0, k
= 7; i
< 8; i
++, k
--) bc
[i
] = dv
[k
];
691 else if (length
== 4) {
692 if (tmp
== 0.0) memset(bc
, 0, 4);
693 else if (tmp
== -0.0) {
698 #if defined __sparc__ || defined __sparc
705 dv
= (unsigned char *) &tmp
;
706 bc
[0] = dv
[index
] & 0x80;
707 int exponent
= dv
[index
] & 0x7F;
710 exponent
+= (dv
[index
] & 0xF0) >> 4;
713 if (exponent
> 127) {
714 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR
,
715 "The float value '%f' is out of the range of "
716 "the single precision: %s", (double)float_value
, p_td
.name
);
720 else if (exponent
< -127) {
721 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_FLOAT_TR
,
722 "The float value '%f' is too small to represent it "
723 "in single precision: %s", (double)float_value
, p_td
.name
);
727 else exponent
+= 127;
728 bc
[0] |= (exponent
>> 1) & 0x7F;
729 bc
[1] = ((exponent
<< 7) & 0x80) | ((dv
[index
] & 0x0F) << 3)
730 | ((dv
[index
+ adj
] & 0xE0) >> 5);
732 bc
[2] = ((dv
[index
] & 0x1F) << 3) | ((dv
[index
+ adj
] & 0xE0) >> 5);
734 bc
[3] = ((dv
[index
] & 0x1F) << 3) | ((dv
[index
+ adj
] & 0xE0) >> 5);
738 TTCN_EncDec_ErrorContext::error_internal("Invalid FLOAT length %d", length
);
740 return myleaf
.length
= p_td
.raw
->fieldlength
;
743 int FLOAT::RAW_decode(const TTCN_Typedescriptor_t
& p_td
, TTCN_Buffer
& buff
,
744 int limit
, raw_order_t top_bit_ord
, boolean no_err
, int /*sel_field*/,
745 boolean
/*first_call*/)
747 int prepaddlength
= buff
.increase_pos_padd(p_td
.raw
->prepadding
);
749 limit
-= prepaddlength
;
750 int decode_length
= p_td
.raw
->fieldlength
;
751 if ( p_td
.raw
->fieldlength
> limit
752 || p_td
.raw
->fieldlength
> (int) buff
.unread_len_bit()) {
753 if (no_err
) return -1;
754 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR
,
755 "There is not enough bits in the buffer to decode type %s.", p_td
.name
);
756 decode_length
= limit
> (int) buff
.unread_len_bit()
757 ? buff
.unread_len_bit() : limit
;
760 decode_length
+= buff
.increase_pos_padd(p_td
.raw
->padding
);
761 return decode_length
+ prepaddlength
;
764 unsigned char data
[16];
766 boolean orders
= FALSE
;
767 if (p_td
.raw
->bitorderinoctet
== ORDER_MSB
) orders
= TRUE
;
768 if (p_td
.raw
->bitorderinfield
== ORDER_MSB
) orders
= !orders
;
769 cp
.bitorder
= orders
? ORDER_MSB
: ORDER_LSB
;
771 if (p_td
.raw
->byteorder
== ORDER_MSB
) orders
= TRUE
;
772 if (p_td
.raw
->bitorderinfield
== ORDER_MSB
) orders
= !orders
;
773 cp
.byteorder
= orders
? ORDER_MSB
: ORDER_LSB
;
774 cp
.fieldorder
= p_td
.raw
->fieldorder
;
775 cp
.hexorder
= ORDER_LSB
;
776 buff
.get_b((size_t) decode_length
, data
, cp
, top_bit_ord
);
777 if (decode_length
== 64) {
778 dv
= (unsigned char *) &tmp
;
779 #if defined __sparc__ || defined __sparc
782 for (int i
= 0, k
= 7; i
< 8; i
++, k
--) dv
[i
] = data
[k
];
785 if (no_err
) return -1;
786 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR
,
787 "Not a Number received for type %s.", p_td
.name
);
791 else if (decode_length
== 32) {
792 int sign
= (data
[0] & 0x80) >> 7;
793 int exponent
= ((data
[0] & 0x7F) << 1) | ((data
[1] & 0x80) >> 7);
794 int fraction
= ((data
[1] & 0x7F) << 1) | ((data
[2] & 0x80) >> 7);
796 fraction
+= ((data
[2] & 0x7F) << 1) | ((data
[3] & 0x80) >> 7);
798 fraction
+= data
[3] & 0x7F;
799 if (exponent
== 0 && fraction
== 0) tmp
= sign
? -0.0 : 0.0;
800 else if (exponent
== 0xFF && fraction
!= 0) {
801 if (no_err
) return -1;
802 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_LEN_ERR
,
803 "Not a Number received for type %s.", p_td
.name
);
806 else if (exponent
== 0 && fraction
!= 0) {
807 double sign_v
= sign
? -1.0 : 1.0;
808 tmp
= sign_v
* (static_cast<double> (fraction
) / 8388608.0)
812 double sign_v
= sign
? -1.0 : 1.0;
814 tmp
= sign_v
* (1.0 + static_cast<double> (fraction
) / 8388608.0)
815 * pow(2.0, static_cast<double> (exponent
));
819 decode_length
+= buff
.increase_pos_padd(p_td
.raw
->padding
);
822 return decode_length
+ prepaddlength
;
825 int FLOAT::XER_encode(const XERdescriptor_t
& p_td
,
826 TTCN_Buffer
& p_buf
, unsigned int flavor
, int indent
, embed_values_enc_struct_t
*) const
829 TTCN_EncDec_ErrorContext::error(
830 TTCN_EncDec::ET_UNBOUND
, "Encoding an unbound float value.");
832 int exer
= is_exer(flavor
|= SIMPLE_TYPE
);
833 // SIMPLE_TYPE has no influence on is_exer, we set it for later
834 int encoded_length
=(int)p_buf
.get_len();
835 flavor
&= ~XER_RECOF
; // float doesn't care
837 begin_xml(p_td
, p_buf
, flavor
, indent
, false);
839 if (exer
&& (p_td
.xer_bits
& XER_DECIMAL
)) {
841 int n
= snprintf(buf
, sizeof(buf
), "%f", (double)float_value
);
842 p_buf
.put_s((size_t)n
, (const unsigned char*)buf
);
845 CHARSTRING value
= float2str(float_value
);
846 p_buf
.put_string(value
);
849 end_xml(p_td
, p_buf
, flavor
, indent
, false);
851 return (int)p_buf
.get_len() - encoded_length
;
854 boolean
FLOAT::is_float(const char* p_str
)
856 bool first_digit
= false; // first digit reached
857 bool decimal_point
= false; // decimal point (.) reached
858 bool exponent_mark
= false; // exponential mark (e or E) reached
859 bool exponent_sign
= false; // sign of the exponential (- or +) reached
861 if ('-' == *p_str
|| '+' == *p_str
) {
865 while (0 != *p_str
) {
868 if (decimal_point
|| exponent_mark
|| !first_digit
) {
871 decimal_point
= true;
876 if (exponent_mark
|| !first_digit
) {
879 exponent_mark
= true;
896 if (exponent_sign
|| !exponent_mark
|| first_digit
) {
899 exponent_sign
= true;
910 int FLOAT::XER_decode(const XERdescriptor_t
& p_td
, XmlReaderWrap
& reader
,
911 unsigned int flavor
, unsigned int /*flavor2*/, embed_values_dec_struct_t
*)
914 int exer
= is_exer(flavor
);
915 int success
= reader
.Ok(), depth
= -1;
916 if (success
<= 0) return 0;
917 boolean own_tag
= !(exer
&& (p_td
.xer_bits
& UNTAGGED
)) && !is_exerlist(flavor
);
919 if (!own_tag
) goto tagless
;
920 if (exer
&& (p_td
.xer_bits
& XER_ATTRIBUTE
)) {
921 verify_name(reader
, p_td
, exer
);
923 const char * value
= (const char *)reader
.Value();
925 if (value
&& is_float(value
)) {
927 sscanf(value
, "%lf", &float_value
);
930 // Let the caller do reader.AdvanceAttribute();
933 for (; success
== 1; success
= reader
.Read()) {
934 int type
= reader
.NodeType();
935 if (XML_READER_TYPE_ELEMENT
== type
) {
936 verify_name(reader
, p_td
, exer
);
937 if (reader
.IsEmptyElement()) {
938 if (exer
&& p_td
.dfeValue
!= 0) {
939 *this = *static_cast<const FLOAT
*>(p_td
.dfeValue
);
944 depth
= reader
.Depth();
946 else if (XML_READER_TYPE_TEXT
== type
&& depth
!= -1) {
947 const char * value
= (const char*)reader
.Value();
948 if (value
&& is_float(value
)) {
950 sscanf(value
, "%lf", &float_value
);
953 else if (XML_READER_TYPE_END_ELEMENT
== type
) {
954 verify_end(reader
, p_td
, depth
, exer
);
955 if (!bound_flag
&& exer
&& p_td
.dfeValue
!= 0) {
956 *this = *static_cast<const FLOAT
*>(p_td
.dfeValue
);
962 } // if not attribute
963 return 1; // decode successful
966 const char* POS_INF_STR
= "\"infinity\"";
967 const char* NEG_INF_STR
= "\"-infinity\"";
968 const char* NAN_STR
= "\"not_a_number\"";
970 int FLOAT::JSON_encode(const TTCN_Typedescriptor_t
&, JSON_Tokenizer
& p_tok
) const
973 TTCN_EncDec_ErrorContext::error(TTCN_EncDec::ET_UNBOUND
,
974 "Encoding an unbound float value.");
978 double value
= (double)float_value
;
979 if ((double)INFINITY
== value
) {
980 return p_tok
.put_next_token(JSON_TOKEN_STRING
, POS_INF_STR
);
982 if (-(double)INFINITY
== value
) {
983 return p_tok
.put_next_token(JSON_TOKEN_STRING
, NEG_INF_STR
);
986 return p_tok
.put_next_token(JSON_TOKEN_STRING
, NAN_STR
);
989 // true if decimal representation possible (use %f format)
990 bool decimal_repr
= (value
== 0.0)
991 || (value
> -MAX_DECIMAL_FLOAT
&& value
<= -MIN_DECIMAL_FLOAT
)
992 || (value
>= MIN_DECIMAL_FLOAT
&& value
< MAX_DECIMAL_FLOAT
);
994 char* tmp_str
= mprintf(decimal_repr
? "%f" : "%e", value
);
995 int enc_len
= p_tok
.put_next_token(JSON_TOKEN_NUMBER
, tmp_str
);
1000 int FLOAT::JSON_decode(const TTCN_Typedescriptor_t
& p_td
, JSON_Tokenizer
& p_tok
, boolean p_silent
)
1003 json_token_t token
= JSON_TOKEN_NONE
;
1005 size_t value_len
= 0;
1007 boolean use_default
= p_td
.json
->default_value
&& 0 == p_tok
.get_buffer_length();
1009 // No JSON data in the buffer -> use default value
1010 value
= (char*)p_td
.json
->default_value
;
1011 value_len
= strlen(value
);
1013 dec_len
= p_tok
.get_next_token(&token
, &value
, &value_len
);
1015 if (JSON_TOKEN_ERROR
== token
) {
1016 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG
, JSON_DEC_BAD_TOKEN_ERROR
, "");
1017 return JSON_ERROR_FATAL
;
1019 else if (JSON_TOKEN_STRING
== token
|| use_default
) {
1020 if (0 == strncmp(value
, POS_INF_STR
+ (use_default
? 1 : 0), value_len
)) {
1022 float_value
= INFINITY
;
1024 else if (0 == strncmp(value
, NEG_INF_STR
+ (use_default
? 1 : 0), value_len
)) {
1026 float_value
= -INFINITY
;
1028 else if (0 == strncmp(value
, NAN_STR
+ (use_default
? 1 : 0), value_len
)) {
1033 float_value
= INFINITY
+ (-INFINITY
);
1036 else if (!use_default
) {
1037 char* spec_val
= mprintf("float (%s, %s or %s)", POS_INF_STR
, NEG_INF_STR
, NAN_STR
);
1038 JSON_ERROR(TTCN_EncDec::ET_INVAL_MSG
, JSON_DEC_FORMAT_ERROR
, "string", spec_val
);
1041 return JSON_ERROR_FATAL
;
1044 else if (JSON_TOKEN_NUMBER
== token
) {
1045 char* value2
= mcopystrn(value
, value_len
);
1046 sscanf(value2
, "%lf", &float_value
);
1050 return JSON_ERROR_INVALID_TOKEN
;
1052 if (!bound_flag
&& use_default
) {
1053 // Already checked the default value for the string possibilities, now
1054 // check for a valid number
1055 char* value2
= mcopystrn(value
, value_len
);
1056 sscanf(value2
, "%lf", &float_value
);
1066 double operator+(double double_value
, const FLOAT
& other_value
)
1068 other_value
.must_bound("Unbound right operand of float addition.");
1069 FLOAT::check_numeric(double_value
, "Left operand of float addition");
1070 FLOAT::check_numeric(other_value
.float_value
, "Right operand of float addition");
1071 return double_value
+ other_value
.float_value
;
1074 double operator-(double double_value
, const FLOAT
& other_value
)
1076 other_value
.must_bound("Unbound right operand of float subtraction.");
1077 FLOAT::check_numeric(double_value
, "Left operand of float subtraction");
1078 FLOAT::check_numeric(other_value
.float_value
, "Right operand of float subtraction");
1079 return double_value
- other_value
.float_value
;
1082 double operator*(double double_value
, const FLOAT
& other_value
)
1084 other_value
.must_bound("Unbound right operand of float multiplication.");
1085 FLOAT::check_numeric(double_value
, "Left operand of float multiplication");
1086 FLOAT::check_numeric(other_value
.float_value
, "Right operand of float multiplication");
1087 return double_value
* other_value
.float_value
;
1090 double operator/(double double_value
, const FLOAT
& other_value
)
1092 other_value
.must_bound("Unbound right operand of float division.");
1093 FLOAT::check_numeric(double_value
, "Left operand of float division");
1094 FLOAT::check_numeric(other_value
.float_value
, "Right operand of float division");
1095 if (other_value
.float_value
== 0.0) TTCN_error("Float division by zero.");
1096 return double_value
/ other_value
.float_value
;
1099 boolean
operator==(double double_value
, const FLOAT
& other_value
)
1101 other_value
.must_bound("Unbound right operand of float comparison.");
1102 return double_value
== other_value
.float_value
;
1105 boolean
operator<(double double_value
, const FLOAT
& other_value
)
1107 other_value
.must_bound("Unbound right operand of float comparison.");
1108 return double_value
< other_value
.float_value
;
1111 boolean
operator>(double double_value
, const FLOAT
& other_value
)
1113 other_value
.must_bound("Unbound right operand of float comparison.");
1114 return double_value
> other_value
.float_value
;
1117 // float template class
1119 void FLOAT_template::clean_up()
1121 if (template_selection
== VALUE_LIST
||
1122 template_selection
== COMPLEMENTED_LIST
)
1123 delete [] value_list
.list_value
;
1124 template_selection
= UNINITIALIZED_TEMPLATE
;
1127 void FLOAT_template::copy_template(const FLOAT_template
& other_value
)
1129 switch (other_value
.template_selection
) {
1130 case SPECIFIC_VALUE
:
1131 single_value
= other_value
.single_value
;
1138 case COMPLEMENTED_LIST
:
1139 value_list
.n_values
= other_value
.value_list
.n_values
;
1140 value_list
.list_value
= new FLOAT_template
[value_list
.n_values
];
1141 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
1142 value_list
.list_value
[i
].copy_template(
1143 other_value
.value_list
.list_value
[i
]);
1146 value_range
= other_value
.value_range
;
1149 TTCN_error("Copying an uninitialized/unsupported float template.");
1151 set_selection(other_value
);
1154 FLOAT_template::FLOAT_template()
1159 FLOAT_template::FLOAT_template(template_sel other_value
)
1160 : Base_Template(other_value
)
1162 check_single_selection(other_value
);
1165 FLOAT_template::FLOAT_template(double other_value
)
1166 : Base_Template(SPECIFIC_VALUE
)
1168 single_value
= other_value
;
1171 FLOAT_template::FLOAT_template(const FLOAT
& other_value
)
1172 : Base_Template(SPECIFIC_VALUE
)
1174 other_value
.must_bound("Creating a template from an unbound float value.");
1175 single_value
= other_value
.float_value
;
1178 FLOAT_template::FLOAT_template(const OPTIONAL
<FLOAT
>& other_value
)
1180 switch (other_value
.get_selection()) {
1181 case OPTIONAL_PRESENT
:
1182 set_selection(SPECIFIC_VALUE
);
1183 single_value
= (double)(const FLOAT
&)other_value
;
1186 set_selection(OMIT_VALUE
);
1189 TTCN_error("Creating a float template from an unbound optional field.");
1193 FLOAT_template::FLOAT_template(const FLOAT_template
& other_value
)
1196 copy_template(other_value
);
1199 FLOAT_template::~FLOAT_template()
1204 FLOAT_template
& FLOAT_template::operator=(template_sel other_value
)
1206 check_single_selection(other_value
);
1208 set_selection(other_value
);
1212 FLOAT_template
& FLOAT_template::operator=(double other_value
)
1215 set_selection(SPECIFIC_VALUE
);
1216 single_value
= other_value
;
1220 FLOAT_template
& FLOAT_template::operator=(const FLOAT
& other_value
)
1222 other_value
.must_bound("Assignment of an unbound float value "
1225 set_selection(SPECIFIC_VALUE
);
1226 single_value
= other_value
.float_value
;
1230 FLOAT_template
& FLOAT_template::operator=(const OPTIONAL
<FLOAT
>& other_value
)
1233 switch (other_value
.get_selection()) {
1234 case OPTIONAL_PRESENT
:
1235 set_selection(SPECIFIC_VALUE
);
1236 single_value
= (double)(const FLOAT
&)other_value
;
1239 set_selection(OMIT_VALUE
);
1242 TTCN_error("Assignment of an unbound optional field to a float template.");
1247 FLOAT_template
& FLOAT_template::operator=(const FLOAT_template
& other_value
)
1249 if (&other_value
!= this) {
1251 copy_template(other_value
);
1256 boolean
FLOAT_template::match(double other_value
, boolean
/* legacy */) const
1258 switch (template_selection
) {
1259 case SPECIFIC_VALUE
:
1260 return single_value
== other_value
|| // check if they're both NaN
1261 (single_value
!= single_value
&& other_value
!= other_value
);
1268 case COMPLEMENTED_LIST
:
1269 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
1270 if(value_list
.list_value
[i
].match(other_value
))
1271 return template_selection
== VALUE_LIST
;
1272 return template_selection
== COMPLEMENTED_LIST
;
1274 return (!value_range
.min_is_present
||
1275 value_range
.min_value
<= other_value
) &&
1276 (!value_range
.max_is_present
||
1277 value_range
.max_value
>= other_value
);
1279 TTCN_error("Matching with an uninitialized/unsupported float template.");
1284 boolean
FLOAT_template::match(const FLOAT
& other_value
, boolean
/* legacy */) const
1286 if (!other_value
.is_bound()) return FALSE
;
1287 return match(other_value
.float_value
);
1291 void FLOAT_template::set_type(template_sel template_type
,
1292 unsigned int list_length
)
1295 switch (template_type
) {
1297 case COMPLEMENTED_LIST
:
1298 set_selection(template_type
);
1299 value_list
.n_values
= list_length
;
1300 value_list
.list_value
= new FLOAT_template
[list_length
];
1303 set_selection(VALUE_RANGE
);
1304 value_range
.min_is_present
= FALSE
;
1305 value_range
.max_is_present
= FALSE
;
1308 TTCN_error("Setting an invalid type for a float template.");
1312 FLOAT_template
& FLOAT_template::list_item(unsigned int list_index
)
1314 if (template_selection
!= VALUE_LIST
&&
1315 template_selection
!= COMPLEMENTED_LIST
)
1316 TTCN_error("Accessing a list element of a non-list float template.");
1317 if (list_index
>= value_list
.n_values
)
1318 TTCN_error("Index overflow in a float value list template.");
1319 return value_list
.list_value
[list_index
];
1322 void FLOAT_template::set_min(double min_value
)
1324 if (template_selection
!= VALUE_RANGE
)
1325 TTCN_error("Float template is not range when setting lower limit.");
1326 if (value_range
.max_is_present
&& value_range
.max_value
< min_value
)
1327 TTCN_error("The lower limit of the range is greater than the "
1328 "upper limit in a float template.");
1329 value_range
.min_is_present
= TRUE
;
1330 value_range
.min_value
= min_value
;
1333 void FLOAT_template::set_min(const FLOAT
& min_value
)
1335 min_value
.must_bound("Using an unbound value when setting the lower bound "
1336 "in a float range template.");
1337 set_min(min_value
.float_value
);
1340 void FLOAT_template::set_max(double max_value
)
1342 if (template_selection
!= VALUE_RANGE
)
1343 TTCN_error("Float template is not range when setting upper limit.");
1344 if (value_range
.min_is_present
&& value_range
.min_value
> max_value
)
1345 TTCN_error("The upper limit of the range is smaller than the "
1346 "lower limit in a float template.");
1347 value_range
.max_is_present
= TRUE
;
1348 value_range
.max_value
= max_value
;
1351 void FLOAT_template::set_max(const FLOAT
& max_value
)
1353 max_value
.must_bound("Using an unbound value when setting the upper bound "
1354 "in a float range template.");
1355 set_max(max_value
.float_value
);
1358 double FLOAT_template::valueof() const
1360 if (template_selection
!= SPECIFIC_VALUE
|| is_ifpresent
)
1361 TTCN_error("Performing a valueof "
1362 "or send operation on a non-specific float template.");
1363 return single_value
;
1366 void FLOAT_template::log() const
1368 switch (template_selection
) {
1369 case SPECIFIC_VALUE
:
1370 log_float(single_value
);
1372 case COMPLEMENTED_LIST
:
1373 TTCN_Logger::log_event_str("complement ");
1376 TTCN_Logger::log_char('(');
1377 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++) {
1378 if (i
> 0) TTCN_Logger::log_event_str(", ");
1379 value_list
.list_value
[i
].log();
1381 TTCN_Logger::log_char(')');
1384 TTCN_Logger::log_char('(');
1385 if (value_range
.min_is_present
) log_float(value_range
.min_value
);
1386 else TTCN_Logger::log_event_str("-infinity");
1387 TTCN_Logger::log_event_str(" .. ");
1388 if (value_range
.max_is_present
) log_float(value_range
.max_value
);
1389 else TTCN_Logger::log_event_str("infinity");
1390 TTCN_Logger::log_char(')');
1399 void FLOAT_template::log_match(const FLOAT
& match_value
,
1400 boolean
/* legacy */) const
1402 if (TTCN_Logger::VERBOSITY_COMPACT
== TTCN_Logger::get_matching_verbosity()
1403 && TTCN_Logger::get_logmatch_buffer_len() != 0) {
1404 TTCN_Logger::print_logmatch_buffer();
1405 TTCN_Logger::log_event_str(" := ");
1408 TTCN_Logger::log_event_str(" with ");
1410 if (match(match_value
)) TTCN_Logger::log_event_str(" matched");
1411 else TTCN_Logger::log_event_str(" unmatched");
1414 void FLOAT_template::set_param(Module_Param
& param
) {
1415 param
.basic_check(Module_Param::BC_TEMPLATE
, "float template");
1416 Module_Param_Ptr mp
= ¶m
;
1417 if (param
.get_type() == Module_Param::MP_Reference
) {
1418 mp
= param
.get_referenced_param();
1420 switch (mp
->get_type()) {
1421 case Module_Param::MP_Omit
:
1424 case Module_Param::MP_Any
:
1427 case Module_Param::MP_AnyOrNone
:
1428 *this = ANY_OR_OMIT
;
1430 case Module_Param::MP_List_Template
:
1431 case Module_Param::MP_ComplementList_Template
: {
1432 FLOAT_template temp
;
1433 temp
.set_type(mp
->get_type() == Module_Param::MP_List_Template
?
1434 VALUE_LIST
: COMPLEMENTED_LIST
, mp
->get_size());
1435 for (size_t i
=0; i
<mp
->get_size(); i
++) {
1436 temp
.list_item(i
).set_param(*mp
->get_elem(i
));
1440 case Module_Param::MP_Float
:
1441 *this = mp
->get_float();
1443 case Module_Param::MP_FloatRange
:
1444 set_type(VALUE_RANGE
);
1445 if (mp
->has_lower_float()) set_min(mp
->get_lower_float());
1446 if (mp
->has_upper_float()) set_max(mp
->get_upper_float());
1448 case Module_Param::MP_Expression
:
1449 switch (mp
->get_expr_type()) {
1450 case Module_Param::EXPR_NEGATE
: {
1452 operand
.set_param(*mp
->get_operand1());
1455 case Module_Param::EXPR_ADD
: {
1456 FLOAT operand1
, operand2
;
1457 operand1
.set_param(*mp
->get_operand1());
1458 operand2
.set_param(*mp
->get_operand2());
1459 *this = operand1
+ operand2
;
1461 case Module_Param::EXPR_SUBTRACT
: {
1462 FLOAT operand1
, operand2
;
1463 operand1
.set_param(*mp
->get_operand1());
1464 operand2
.set_param(*mp
->get_operand2());
1465 *this = operand1
- operand2
;
1467 case Module_Param::EXPR_MULTIPLY
: {
1468 FLOAT operand1
, operand2
;
1469 operand1
.set_param(*mp
->get_operand1());
1470 operand2
.set_param(*mp
->get_operand2());
1471 *this = operand1
* operand2
;
1473 case Module_Param::EXPR_DIVIDE
: {
1474 FLOAT operand1
, operand2
;
1475 operand1
.set_param(*mp
->get_operand1());
1476 operand2
.set_param(*mp
->get_operand2());
1477 if (operand2
== 0.0) {
1478 param
.error("Floating point division by zero.");
1480 *this = operand1
/ operand2
;
1483 param
.expr_type_error("a float");
1488 param
.type_error("float template");
1490 is_ifpresent
= param
.get_ifpresent() || mp
->get_ifpresent();
1493 Module_Param
* FLOAT_template::get_param(Module_Param_Name
& param_name
) const
1495 Module_Param
* mp
= NULL
;
1496 switch (template_selection
) {
1497 case UNINITIALIZED_TEMPLATE
:
1498 mp
= new Module_Param_Unbound();
1501 mp
= new Module_Param_Omit();
1504 mp
= new Module_Param_Any();
1507 mp
= new Module_Param_AnyOrNone();
1509 case SPECIFIC_VALUE
:
1510 mp
= new Module_Param_Float(single_value
);
1513 case COMPLEMENTED_LIST
: {
1514 if (template_selection
== VALUE_LIST
) {
1515 mp
= new Module_Param_List_Template();
1518 mp
= new Module_Param_ComplementList_Template();
1520 for (size_t i
= 0; i
< value_list
.n_values
; ++i
) {
1521 mp
->add_elem(value_list
.list_value
[i
].get_param(param_name
));
1525 mp
= new Module_Param_FloatRange(
1526 value_range
.min_value
, value_range
.min_is_present
,
1527 value_range
.max_value
, value_range
.max_is_present
);
1533 mp
->set_ifpresent();
1538 void FLOAT_template::encode_text(Text_Buf
& text_buf
) const
1540 encode_text_base(text_buf
);
1541 switch (template_selection
) {
1546 case SPECIFIC_VALUE
:
1547 text_buf
.push_double(single_value
);
1550 case COMPLEMENTED_LIST
:
1551 text_buf
.push_int(value_list
.n_values
);
1552 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
1553 value_list
.list_value
[i
].encode_text(text_buf
);
1556 text_buf
.push_int(value_range
.min_is_present
? 1 : 0);
1557 if (value_range
.min_is_present
)
1558 text_buf
.push_double(value_range
.min_value
);
1559 text_buf
.push_int(value_range
.max_is_present
? 1 : 0);
1560 if (value_range
.max_is_present
)
1561 text_buf
.push_double(value_range
.max_value
);
1564 TTCN_error("Text encoder: Encoding an undefined/unsupported "
1569 void FLOAT_template::decode_text(Text_Buf
& text_buf
)
1572 decode_text_base(text_buf
);
1573 switch (template_selection
) {
1578 case SPECIFIC_VALUE
:
1579 single_value
= text_buf
.pull_double();
1582 case COMPLEMENTED_LIST
:
1583 value_list
.n_values
= text_buf
.pull_int().get_val();
1584 value_list
.list_value
= new FLOAT_template
[value_list
.n_values
];
1585 for (unsigned int i
= 0; i
< value_list
.n_values
; i
++)
1586 value_list
.list_value
[i
].decode_text(text_buf
);
1589 value_range
.min_is_present
= text_buf
.pull_int() != 0;
1590 if (value_range
.min_is_present
)
1591 value_range
.min_value
= text_buf
.pull_double();
1592 value_range
.max_is_present
= text_buf
.pull_int() != 0;
1593 if (value_range
.max_is_present
)
1594 value_range
.max_value
= text_buf
.pull_double();
1597 TTCN_error("Text decoder: An unknown/unsupported selection was "
1598 "received for a float template.");
1602 boolean
FLOAT_template::is_present(boolean legacy
/* = FALSE */) const
1604 if (template_selection
==UNINITIALIZED_TEMPLATE
) return FALSE
;
1605 return !match_omit(legacy
);
1608 boolean
FLOAT_template::match_omit(boolean legacy
/* = FALSE */) const
1610 if (is_ifpresent
) return TRUE
;
1611 switch (template_selection
) {
1616 case COMPLEMENTED_LIST
:
1618 // legacy behavior: 'omit' can appear in the value/complement list
1619 for (unsigned int i
=0; i
<value_list
.n_values
; i
++)
1620 if (value_list
.list_value
[i
].match_omit())
1621 return template_selection
==VALUE_LIST
;
1622 return template_selection
==COMPLEMENTED_LIST
;
1624 // else fall through
1631 #ifndef TITAN_RUNTIME_2
1632 void FLOAT_template::check_restriction(template_res t_res
, const char* t_name
,
1633 boolean legacy
/* = FALSE */) const
1635 if (template_selection
==UNINITIALIZED_TEMPLATE
) return;
1636 switch ((t_name
&&(t_res
==TR_VALUE
))?TR_OMIT
:t_res
) {
1638 if (!is_ifpresent
&& template_selection
==SPECIFIC_VALUE
) return;
1641 if (!is_ifpresent
&& (template_selection
==OMIT_VALUE
||
1642 template_selection
==SPECIFIC_VALUE
)) return;
1645 if (!match_omit(legacy
)) return;
1650 TTCN_error("Restriction `%s' on template of type %s violated.",
1651 get_res_name(t_res
), t_name
? t_name
: "float");