Skip to content

Integer representation specification - #182

Merged
phax merged 18 commits into
phax:masterfrom
glelouet:more_int_format
Aug 30, 2026
Merged

Integer representation specification#182
phax merged 18 commits into
phax:masterfrom
glelouet:more_int_format

Conversation

@glelouet

@glelouet glelouet commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Objective, constraints and explanations

A previous PR already embarked the "base" feature, but this one is cleaner/more detailed, especially regarding sharing settings.

This PR aims at providing ways to represent integer/long format in the generated code.

When we want to write an int, for example "404", with JExpr.lit(404) , we may also want to specify how this value will be written in the resulting code, eg

  1. the base : "404" in decimal, "0624" in octal, "0x194" in hexadecimal
  2. add the positive leading sign , so "+404"
  3. padd for non-decimal base as in "0x00000194"
  4. in the case of hex should we upper/lower case the letters and the "x" in the prefix ?
  5. Then should we add "_" separators, and where ?

In short, "+4_0_4" is just as valid as "0000624".
This set of choices is a "representation" of integers. It's not in the formatting settings, because formatting is project-wide, while those can change on a class or even field basis.

The main use case of those representations are defining them, and using them in int/long fields (a long is just an int with tailing l/L), therefore the building of one received special attention, with default representations available, both to use directly or to be based on.
As constraints, the default representation of an int should produce the same, when possible, as before ; and should impend no performance hit.

Since creating user-specific representation should not modify the default values, they are all records to be read only. Updating a representation's value actually create a new representation with that value updated. The JAtomInt and JAtomLong can be set their representation, and provide a few methods to update specific fields though it replaces the internal representation with an updated copy.

Those representation start with a base, for example octal, then add options, in the order : force positive sign, padding, use lower caps letters, use separators.

Features

Format class

A new IntegerRepresentation record contains information to represent int and long in the code.

Creation

A few default representation are available ; you are recommended to create your own that you use in your own library, since the default ones are not designed to be core part of the lib (they are arbitrary choices so not as stable as choice presentation).

// creation

// use default one, no separator
IntegerRepresentation myIR = IntegerRepresentation.DEFAULT;

// or default decimal one eg 1_000_000L
myIR = IntegerRepresentation.DEC;

// default hexa so 0xAB_CDL
myIR = IntegerRepresentation.HEX;

//specify all params
myIR = new IntegerRepresentation (false,
                                                                                 false,
                                                                                 EIntegerBase.DECIMAL,
                                                                                 0,
                                                                                 null,
                                                                                 0,
                                                                                 1,
                                                                                 true);

Usage

JAtomInteger and JAtomLong have that new field. They extend a common class that allows to manipulate those fields internally, replacing the representation each time.

// usage

var i = new JAtomInt(42, myIR);
i = new JAtomInt(42).representation(myIR)
// change the base to octal
i.octal()
// and add a separator every 3 char
.separateEvery(3)
// force the addition of +
.positiveSign(true);

Formatting process

  1. formatting an integer/long uses a base and creates sign, prefix, body, suffix
  2. sign only present if negative value or representation's positiveSign is true
  3. prefix depends on the base selected. The representation's prefixUpper indicates if use upper or lower case prefix
  4. body is converted from the base , then padded , then separated
  5. suffix is only for LONG . The representation's suffixUpper indicates if use 'L' or 'l'
  6. padded only applied for bases that use it. Decimal does not allow padding.
  7. body separation is either performed with a separator format, or if null using the separateEvery and separateSize fields.
  8. separator format indicates before which char, and how many, separators to add : each '_' indicates one separator to insert, starting from the end.
  9. separateEvery indicates after how many body chars to add separator, and separateSize how many separator each time.

Padding example

(those are the tests)

42 padded 5 is

  • 0b101010 (no padding needed here)
  • 42 (can't pad decimal)
  • 0x0002a (padding in hex)
  • 000052 (padding in octal)

Separator Format example

1000 decimal with format :

  • "X_X" produces "100_0" : only adds a separator before the before-last charater
  • "_xx__x" produces "1_00__0"

@glelouet glelouet added the minor minor-level change : new feature, no breaking change label Jul 24, 2026
@phax

phax commented Jul 24, 2026

Copy link
Copy Markdown
Owner

I really don't think it is useful to provide all this customizability. Putting effort in creating code that is optimized for people but solely read by compilers is imho not a big priority...

@glelouet

Copy link
Copy Markdown
Collaborator Author

It depends. If you work on custom int format, you want to have eg the mask for the different part avail.
Say the format is SRC8_DEST8_BDY8_CRC4_TTL4 then you want to have the body mask
BDY_MASK= 000_00_77_0_0 ;

Also if you want to parse data to build other code from it, it may be better to parse the data faithfully.

@glelouet

Copy link
Copy Markdown
Collaborator Author

Anyhow, it's good it's not released, because I think it needs more thinking.

I will try to have common interface-ish for all number AtomX classes. Even though for example you have only dec and hex representation for fp.

I think I will go for a more complex internal field to represent the formatting, shared for long/int, and another shared for float/double . So IntegerLiteralFormat / FloatingPointLiteralFormat .

@phax

phax commented Jul 24, 2026

Copy link
Copy Markdown
Owner

But try to keep the default case (no formatting, decimal output) as efficient as possible - thx

@glelouet

Copy link
Copy Markdown
Collaborator Author

ok so here is what I want :

  • be able to share the representation among several JAtomInt
  • and also among JAtomLong (as in, same class for both)
  • while still able to modify the JAtomInt individually

So for me it's best to have a record holding the representation params, including the enum base (hex, dec, bin, oct) , but have the already present methods visible on the JAtom to change the record to a new one.
This way we can directly set the whole params, or change then one by one ; and changing them won't impact the instances they are already assigned to.

@glelouet

glelouet commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator Author

Much better this way. We can update the representation internally without changing the signature.
I had an awful lot of copypasta between int and long so I just made a common class. Thinking of it, could be an interface with default values. edit : no, it can't.

@phax

phax commented Jul 25, 2026

Copy link
Copy Markdown
Owner

fyi: I am on vacation next week - so no expectations towards me pls - thx :-)

@glelouet

Copy link
Copy Markdown
Collaborator Author

expectations

I did not expect you would review all the PRs so fast. gladly surprised.

Also it's nice you took the formatting. Will help me focus on the important things.

But yes, I don't expect anything, except that you take care of yourself during your vacations :)

@glelouet glelouet changed the title more int format Integer representation specification Aug 16, 2026
@glelouet
glelouet marked this pull request as ready for review August 27, 2026 13:40
@glelouet

Copy link
Copy Markdown
Collaborator Author

I made a pass on the tests, ready to review.

return (T) this;
}

public IntegerRepresentation representation ()

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer the annotations on the method return types and method parameters. If not, then not

@glelouet glelouet Aug 28, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean add @NonNull on the return ? Sure. Can you do it, or I do it ?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is too cumbersome for you, let me know

public T representation (IntegerRepresentation representation)
{
if (representation != null)
this.representation = representation;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else this.representation = null?

@glelouet glelouet Aug 28, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, representation is @NonNull

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I'd prefer a "if (null) throw" with the parameter - to make sure the contract of the method is clear

// copier

/// Intermediate mutable class for mutate a record. Waiting for java withers …
public static class Copier

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would we spare that, when we change the record to a regular class?

Comment thread jcodemodel/src/main/java/com/helger/jcodemodel/literals/EIntegerBase.java Outdated
Comment thread jcodemodel/src/main/java/com/helger/jcodemodel/literals/EIntegerBase.java Outdated
}

/// @return sb
public StringBuilder represent (int i,

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, this method (and the long variant) would better suit in IntegerRepresentation - otherwise we have some weird circle dependency between them

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@glelouet any comment on this one? Objections again moving it?

reversed.append (source.charAt (i));
break;
}
else

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for else

reversed.append (SEP_CHAR);
else
break;
else

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the block above the else in brackets - this could be very misleading otherwise ;-)

static void checkFormat (String expected, String source, String format, boolean allowLeadingSep)
{
StringBuilder sb = new StringBuilder ();
EIntegerBase.addSep (source, format, allowLeadingSep, 0, 0, sb);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could extend the tests to cover the two "0" parameters as well

@phax
phax merged commit 03ad083 into phax:master Aug 30, 2026
4 checks passed
@glelouet
glelouet deleted the more_int_format branch August 30, 2026 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor minor-level change : new feature, no breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants