Skip to content

Commit

Permalink
feat(core): Size.bytes() (#24136)
Browse files Browse the repository at this point in the history
This PR adds Size.bytes(), which allows to specify a Size class from an amount of bytes. Within the Size class, `Size.bytes( )` is the additional method added here to enable support for bytes as well as conversion to bytes with `Size.toBytes`.

For example, 

```ts
const size = new Size.bytes(1024);
expect(size.toKibibytes).toEqual(1);
```

creates a new object of the Size class with a size of 1024 bytes and which is equivalent to 1 kibibyte.

Closes #24106.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
pattasai committed Feb 15, 2023
1 parent 12e13c1 commit 9b2a45a
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 9 deletions.
41 changes: 32 additions & 9 deletions packages/@aws-cdk/core/lib/size.ts
Expand Up @@ -9,6 +9,17 @@ import { Token } from './token';
* When the amount is passed as a token, unit conversion is not possible.
*/
export class Size {
/**
* Create a Storage representing an amount bytes.
*
* @param amount the amount of bytes to be represented
*
* @returns a new `Size` instance
*/
public static bytes(amount: number): Size {
return new Size(amount, StorageUnit.Bytes);
}

/**
* Create a Storage representing an amount kibibytes.
* 1 KiB = 1024 bytes
Expand Down Expand Up @@ -90,6 +101,17 @@ export class Size {
this.unit = unit;
}

/**
* Return this storage as a total number of bytes.
*
* @param opts the conversion options
*
* @returns the quantity expressed in bytes
*/
public toBytes(opts: SizeConversionOptions = {}): number {
return convert(this.amount, this.unit, StorageUnit.Bytes, opts);
}

/**
* Return this storage as a total number of kibibytes.
*
Expand Down Expand Up @@ -177,13 +199,14 @@ export interface SizeConversionOptions {
}

class StorageUnit {
public static readonly Kibibytes = new StorageUnit('kibibytes', 1);
public static readonly Mebibytes = new StorageUnit('mebibytes', 1024);
public static readonly Gibibytes = new StorageUnit('gibibytes', 1024 * 1024);
public static readonly Tebibytes = new StorageUnit('tebibytes', 1024 * 1024 * 1024);
public static readonly Pebibytes = new StorageUnit('pebibytes', 1024 * 1024 * 1024 * 1024);

private constructor(public readonly label: string, public readonly inKibiBytes: number) {
public static readonly Bytes = new StorageUnit('bytes', 1);
public static readonly Kibibytes = new StorageUnit('kibibytes', 1024);
public static readonly Mebibytes = new StorageUnit('mebibytes', 1024 * 1024);
public static readonly Gibibytes = new StorageUnit('gibibytes', 1024 * 1024 * 1024);
public static readonly Tebibytes = new StorageUnit('tebibytes', 1024 * 1024 * 1024 * 1024);
public static readonly Pebibytes = new StorageUnit('pebibytes', 1024 * 1024 * 1024 * 1024 * 1024);

private constructor(public readonly label: string, public readonly inBytes: number) {
// MAX_SAFE_INTEGER is 2^53, so by representing storage in kibibytes,
// the highest storage we can represent is 8 exbibytes.
}
Expand All @@ -195,12 +218,12 @@ class StorageUnit {

function convert(amount: number, fromUnit: StorageUnit, toUnit: StorageUnit, options: SizeConversionOptions = {}) {
const rounding = options.rounding ?? SizeRoundingBehavior.FAIL;
if (fromUnit.inKibiBytes === toUnit.inKibiBytes) { return amount; }
if (fromUnit.inBytes === toUnit.inBytes) { return amount; }
if (Token.isUnresolved(amount)) {
throw new Error(`Size must be specified as 'Size.${toUnit}()' here since its value comes from a token and cannot be converted (got Size.${fromUnit})`);
}

const multiplier = fromUnit.inKibiBytes / toUnit.inKibiBytes;
const multiplier = fromUnit.inBytes / toUnit.inBytes;
const value = amount * multiplier;
switch (rounding) {
case SizeRoundingBehavior.NONE:
Expand Down
14 changes: 14 additions & 0 deletions packages/@aws-cdk/core/test/size.test.ts
Expand Up @@ -15,6 +15,20 @@ describe('size', () => {
);
});

test('Size in bytes', () => {
const size = Size.bytes(1_099_511_627_776);

expect(size.toBytes()).toEqual(1_099_511_627_776);
expect(size.toKibibytes()).toEqual(1_073_741_824);
expect(size.toMebibytes()).toEqual(1_048_576);
expect(size.toGibibytes()).toEqual(1024);
expect(size.toTebibytes()).toEqual(1);
expect(() => size.toPebibytes()).toThrow(/'1099511627776 bytes' cannot be converted into a whole number/);
floatEqual(size.toPebibytes({ rounding: SizeRoundingBehavior.NONE }), 1_099_511_627_776 / (1024 * 1024 * 1024 * 1024 * 1024));

expect(Size.bytes(4 * 1024 * 1024 * 1024).toGibibytes()).toEqual(4);
});

test('Size in kibibytes', () => {
const size = Size.kibibytes(4_294_967_296);

Expand Down

0 comments on commit 9b2a45a

Please sign in to comment.