From 78eb70802b3262f42186eed221416f20cd52772a Mon Sep 17 00:00:00 2001
From: George Fu <kuhe@users.noreply.github.com>
Date: Fri, 21 Jun 2024 15:44:39 +0000
Subject: [PATCH] stack based encoding

---
 .../core/src/submodules/cbor/cbor-encode.ts   | 47 ++++++++++++-------
 .../core/src/submodules/cbor/cbor.spec.ts     |  8 ++--
 2 files changed, 35 insertions(+), 20 deletions(-)

diff --git a/packages/core/src/submodules/cbor/cbor-encode.ts b/packages/core/src/submodules/cbor/cbor-encode.ts
index 892b25d2e4b..c9cf836ffa5 100644
--- a/packages/core/src/submodules/cbor/cbor-encode.ts
+++ b/packages/core/src/submodules/cbor/cbor-encode.ts
@@ -83,14 +83,21 @@ function encodeHeader(major: CborMajorType, value: Uint64 | number): void {
   }
 }
 
+const headerEncode: Symbol = Symbol("headerEncodeCbor");
+
 /**
  * @param _input - JS data object.
  */
 export function encode(_input: any): void {
-  const encodeQueue = [_input];
+  const encodeStack = [_input];
+
+  while (encodeStack.length) {
+    const input = encodeStack.pop();
+    if (input?.headerEncode === headerEncode) {
+      encodeHeader(input.major, input.count);
+      continue;
+    }
 
-  while (encodeQueue.length) {
-    const input = encodeQueue.shift();
     ensureSpace(typeof input === "string" ? input.length * 4 : 64);
 
     if (typeof input === "string") {
@@ -172,11 +179,14 @@ export function encode(_input: any): void {
       // though the CBOR spec includes it.
       throw new Error("@smithy/core/cbor: client may not serialize undefined value.");
     } else if (Array.isArray(input)) {
-      encodeHeader(majorList, input.length);
-      for (let i = 0; i < input.length; ++i) {
-        // encode(input[i]);
-        encodeQueue.push(input[i]);
+      for (let i = input.length - 1; i >= 0; --i) {
+        encodeStack.push(input[i]);
       }
+      encodeStack.push({
+        headerEncode,
+        major: majorList,
+        count: input.length,
+      });
       continue;
     } else if (typeof input.byteLength === "number") {
       ensureSpace(input.length * 2);
@@ -185,20 +195,25 @@ export function encode(_input: any): void {
       cursor += input.byteLength;
       continue;
     } else if (typeof input === "object" && "tag" in input && "value" in input && Object.keys(input).length === 2) {
-      encodeHeader(majorTag, input.tag);
-      // encode(input.value);
-      encodeQueue.push(input.value);
+      encodeStack.push(input.value);
+      encodeStack.push({
+        headerEncode,
+        major: majorTag,
+        count: input.tag,
+      });
       continue;
     } else if (typeof input === "object") {
       const keys = Object.keys(input);
-      encodeHeader(majorMap, keys.length);
-      for (let i = 0; i < keys.length; ++i) {
+      for (let i = keys.length - 1; i >= 0; --i) {
         const key = keys[i];
-        // encode(key);
-        // encode(input[key]);
-        encodeQueue.push(key);
-        encodeQueue.push(input[key]);
+        encodeStack.push(input[key]);
+        encodeStack.push(key);
       }
+      encodeStack.push({
+        headerEncode,
+        major: majorMap,
+        count: keys.length,
+      });
       continue;
     }
 
diff --git a/packages/core/src/submodules/cbor/cbor.spec.ts b/packages/core/src/submodules/cbor/cbor.spec.ts
index 3e1bf157678..d0532475625 100644
--- a/packages/core/src/submodules/cbor/cbor.spec.ts
+++ b/packages/core/src/submodules/cbor/cbor.spec.ts
@@ -192,10 +192,10 @@ describe("cbor", () => {
       },
       cbor: allocByteArray([
         164, 102, 110, 117, 109, 98, 101, 114, 27, 0, 0, 122, 204, 161, 196, 74, 227, 103, 109, 101, 115, 115, 97, 103,
-        101, 108, 104, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 100, 108, 105, 115, 116, 131, 99, 109, 97,
-        112, 163, +0, +244, +161, 97, 97, 97, 97, 97, 98, 97, 98, 101, 105, 116, 101, 109, 115, 136, +97, +97, +97, +98,
-        0, 32, 245, 244, 246, 96, 100, 116, 101, 115, 116, 130, 109, 110, 101, 115, 116, 101, 100, 32, 105, 116, 101,
-        109, 32, 65, 109, 110, 101, 115, 116, 101, 100, 32, 105, 116, 101, 109, 32, 66,
+        101, 108, 104, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 100, 108, 105, 115, 116, 131, 0, 244, 161,
+        97, 97, 97, 98, 99, 109, 97, 112, 163, 97, 97, 97, 97, 97, 98, 97, 98, 101, 105, 116, 101, 109, 115, 136, 0, 32,
+        245, 244, 246, 96, 100, 116, 101, 115, 116, 130, 109, 110, 101, 115, 116, 101, 100, 32, 105, 116, 101, 109, 32,
+        65, 109, 110, 101, 115, 116, 101, 100, 32, 105, 116, 101, 109, 32, 66,
       ]),
     },
   ];