[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 5/6] Convert CPU APIs to use virArch



From: "Daniel P. Berrange" <berrange redhat com>

Signed-off-by: Daniel P. Berrange <berrange redhat com>
---
 src/conf/cpu_conf.c          | 24 +++++++++++++++---------
 src/conf/cpu_conf.h          |  3 ++-
 src/cpu/cpu.c                | 40 ++++++++++++++++++++--------------------
 src/cpu/cpu.h                | 11 ++++++-----
 src/cpu/cpu_arm.c            |  2 +-
 src/cpu/cpu_generic.c        | 10 ++++++----
 src/cpu/cpu_powerpc.c        | 14 +++++++-------
 src/cpu/cpu_s390.c           |  2 +-
 src/cpu/cpu_x86.c            | 18 +++++++++---------
 src/qemu/qemu_capabilities.c | 10 +++++-----
 src/qemu/qemu_command.c      |  8 ++++----
 src/vmware/vmware_conf.c     | 12 +++++-------
 12 files changed, 81 insertions(+), 73 deletions(-)

diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
index 8cb54a3..2b3b44d 100644
--- a/src/conf/cpu_conf.c
+++ b/src/conf/cpu_conf.c
@@ -79,7 +79,6 @@ virCPUDefFree(virCPUDefPtr def)
     if (!def)
         return;
 
-    VIR_FREE(def->arch);
     virCPUDefFreeModel(def);
 
     for (i = 0 ; i < def->ncells ; i++) {
@@ -148,9 +147,7 @@ virCPUDefCopy(const virCPUDefPtr cpu)
     copy->sockets = cpu->sockets;
     copy->cores = cpu->cores;
     copy->threads = cpu->threads;
-
-    if (cpu->arch && !(copy->arch = strdup(cpu->arch)))
-        goto no_memory;
+    copy->arch = cpu->arch;
 
     if (virCPUDefCopyModel(copy, cpu, false) < 0)
         goto error;
@@ -269,12 +266,19 @@ virCPUDefParseXML(const xmlNodePtr node,
     }
 
     if (def->type == VIR_CPU_TYPE_HOST) {
-        def->arch = virXPathString("string(./arch[1])", ctxt);
-        if (!def->arch) {
+        char *arch = virXPathString("string(./arch[1])", ctxt);
+        if (!arch) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            "%s", _("Missing CPU architecture"));
             goto error;
         }
+        if ((def->arch = virArchFromString(arch)) == VIR_ARCH_NONE) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Unknown architecture %s"), arch);
+            VIR_FREE(arch);
+            goto error;
+        }
+        VIR_FREE(arch);
     }
 
     if (!(def->model = virXPathString("string(./model[1])", ctxt)) &&
@@ -560,7 +564,8 @@ virCPUDefFormatBufFull(virBufferPtr buf,
     virBufferAddLit(buf, ">\n");
 
     if (def->arch)
-        virBufferAsprintf(buf, "  <arch>%s</arch>\n", def->arch);
+        virBufferAsprintf(buf, "  <arch>%s</arch>\n",
+                          virArchToString(def->arch));
 
     virBufferAdjustIndent(buf, 2);
     if (virCPUDefFormatBuf(buf, def, flags) < 0)
@@ -740,10 +745,11 @@ virCPUDefIsEqual(virCPUDefPtr src,
         goto cleanup;
     }
 
-    if (STRNEQ_NULLABLE(src->arch, dst->arch)) {
+    if (src->arch != dst->arch) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("Target CPU arch %s does not match source %s"),
-                       NULLSTR(dst->arch), NULLSTR(src->arch));
+                       virArchToString(dst->arch),
+                       virArchToString(src->arch));
         goto cleanup;
     }
 
diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
index 879f8eb..5bff70e 100644
--- a/src/conf/cpu_conf.h
+++ b/src/conf/cpu_conf.h
@@ -28,6 +28,7 @@
 # include "buf.h"
 # include "xml.h"
 # include "bitmap.h"
+# include "virarch.h"
 
 # define VIR_CPU_VENDOR_ID_LENGTH 12
 
@@ -104,7 +105,7 @@ struct _virCPUDef {
     int type;           /* enum virCPUType */
     int mode;           /* enum virCPUMode */
     int match;          /* enum virCPUMatch */
-    char *arch;
+    virArch arch;
     char *model;
     char *vendor_id;    /* vendor id returned by CPUID in the guest */
     int fallback;       /* enum virCPUFallback */
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
index 4263b88..53c4cc3 100644
--- a/src/cpu/cpu.c
+++ b/src/cpu/cpu.c
@@ -48,12 +48,12 @@ static struct cpuArchDriver *drivers[] = {
 
 
 static struct cpuArchDriver *
-cpuGetSubDriver(const char *arch)
+cpuGetSubDriver(virArch arch)
 {
     unsigned int i;
     unsigned int j;
 
-    if (arch == NULL) {
+    if (arch == VIR_ARCH_NONE) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        "%s", _("undefined hardware architecture"));
         return NULL;
@@ -61,7 +61,7 @@ cpuGetSubDriver(const char *arch)
 
     for (i = 0; i < NR_DRIVERS - 1; i++) {
         for (j = 0; j < drivers[i]->narch; j++) {
-            if (STREQ(arch, drivers[i]->arch[j]))
+            if (arch == drivers[i]->arch[j])
                 return drivers[i];
         }
     }
@@ -120,7 +120,7 @@ cpuCompare(virCPUDefPtr host,
     if (driver->compare == NULL) {
         virReportError(VIR_ERR_NO_SUPPORT,
                        _("cannot compare CPUs of %s architecture"),
-                       host->arch);
+                       virArchToString(host->arch));
         return VIR_CPU_COMPARE_ERROR;
     }
 
@@ -163,7 +163,7 @@ cpuDecode(virCPUDefPtr cpu,
     if (driver->decode == NULL) {
         virReportError(VIR_ERR_NO_SUPPORT,
                        _("cannot decode CPU data for %s architecture"),
-                       cpu->arch);
+                       virArchToString(cpu->arch));
         return -1;
     }
 
@@ -172,7 +172,7 @@ cpuDecode(virCPUDefPtr cpu,
 
 
 int
-cpuEncode(const char *arch,
+cpuEncode(virArch arch,
           const virCPUDefPtr cpu,
           union cpuData **forced,
           union cpuData **required,
@@ -185,7 +185,7 @@ cpuEncode(const char *arch,
 
     VIR_DEBUG("arch=%s, cpu=%p, forced=%p, required=%p, "
               "optional=%p, disabled=%p, forbidden=%p, vendor=%p",
-              NULLSTR(arch), cpu, forced, required,
+              virArchToString(arch), cpu, forced, required,
               optional, disabled, forbidden, vendor);
 
     if ((driver = cpuGetSubDriver(arch)) == NULL)
@@ -194,7 +194,7 @@ cpuEncode(const char *arch,
     if (driver->encode == NULL) {
         virReportError(VIR_ERR_NO_SUPPORT,
                        _("cannot encode CPU data for %s architecture"),
-                       arch);
+                       virArchToString(arch));
         return -1;
     }
 
@@ -204,12 +204,12 @@ cpuEncode(const char *arch,
 
 
 void
-cpuDataFree(const char *arch,
+cpuDataFree(virArch arch,
             union cpuData *data)
 {
     struct cpuArchDriver *driver;
 
-    VIR_DEBUG("arch=%s, data=%p", NULLSTR(arch), data);
+    VIR_DEBUG("arch=%s, data=%p", virArchToString(arch), data);
 
     if (data == NULL)
         return;
@@ -220,7 +220,7 @@ cpuDataFree(const char *arch,
     if (driver->free == NULL) {
         virReportError(VIR_ERR_NO_SUPPORT,
                        _("cannot free CPU data for %s architecture"),
-                       arch);
+                       virArchToString(arch));
         return;
     }
 
@@ -229,11 +229,11 @@ cpuDataFree(const char *arch,
 
 
 union cpuData *
-cpuNodeData(const char *arch)
+cpuNodeData(virArch arch)
 {
     struct cpuArchDriver *driver;
 
-    VIR_DEBUG("arch=%s", NULLSTR(arch));
+    VIR_DEBUG("arch=%s", virArchToString(arch));
 
     if ((driver = cpuGetSubDriver(arch)) == NULL)
         return NULL;
@@ -241,7 +241,7 @@ cpuNodeData(const char *arch)
     if (driver->nodeData == NULL) {
         virReportError(VIR_ERR_NO_SUPPORT,
                        _("cannot get node CPU data for %s architecture"),
-                       arch);
+                       virArchToString(arch));
         return NULL;
     }
 
@@ -265,7 +265,7 @@ cpuGuestData(virCPUDefPtr host,
     if (driver->guestData == NULL) {
         virReportError(VIR_ERR_NO_SUPPORT,
                        _("cannot compute guest CPU data for %s architecture"),
-                       host->arch);
+                       virArchToString(host->arch));
         return VIR_CPU_COMPARE_ERROR;
     }
 
@@ -391,7 +391,7 @@ cpuBaseline(virCPUDefPtr *cpus,
     if (driver->baseline == NULL) {
         virReportError(VIR_ERR_NO_SUPPORT,
                        _("cannot compute baseline CPU of %s architecture"),
-                       cpus[0]->arch);
+                       virArchToString(cpus[0]->arch));
         return NULL;
     }
 
@@ -413,7 +413,7 @@ cpuUpdate(virCPUDefPtr guest,
     if (driver->update == NULL) {
         virReportError(VIR_ERR_NO_SUPPORT,
                        _("cannot update guest CPU data for %s architecture"),
-                       host->arch);
+                       virArchToString(host->arch));
         return -1;
     }
 
@@ -421,14 +421,14 @@ cpuUpdate(virCPUDefPtr guest,
 }
 
 int
-cpuHasFeature(const char *arch,
+cpuHasFeature(virArch arch,
               const union cpuData *data,
               const char *feature)
 {
     struct cpuArchDriver *driver;
 
     VIR_DEBUG("arch=%s, data=%p, feature=%s",
-              arch, data, feature);
+              virArchToString(arch), data, feature);
 
     if ((driver = cpuGetSubDriver(arch)) == NULL)
         return -1;
@@ -436,7 +436,7 @@ cpuHasFeature(const char *arch,
     if (driver->hasFeature == NULL) {
         virReportError(VIR_ERR_NO_SUPPORT,
                        _("cannot check guest CPU data for %s architecture"),
-                       arch);
+                       virArchToString(arch));
         return -1;
     }
 
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
index 01c732c..5153b62 100644
--- a/src/cpu/cpu.h
+++ b/src/cpu/cpu.h
@@ -26,6 +26,7 @@
 
 # include "virterror_internal.h"
 # include "datatypes.h"
+# include "virarch.h"
 # include "conf/cpu_conf.h"
 # include "cpu_x86_data.h"
 # include "cpu_ppc_data.h"
@@ -88,7 +89,7 @@ typedef int
 
 struct cpuArchDriver {
     const char *name;
-    const char **arch;
+    const virArch *arch;
     unsigned int narch;
     cpuArchCompare      compare;
     cpuArchDecode       decode;
@@ -118,7 +119,7 @@ cpuDecode   (virCPUDefPtr cpu,
              const char *preferred);
 
 extern int
-cpuEncode   (const char *arch,
+cpuEncode   (virArch arch,
              const virCPUDefPtr cpu,
              union cpuData **forced,
              union cpuData **required,
@@ -128,11 +129,11 @@ cpuEncode   (const char *arch,
              union cpuData **vendor);
 
 extern void
-cpuDataFree (const char *arch,
+cpuDataFree (virArch arch,
              union cpuData *data);
 
 extern union cpuData *
-cpuNodeData (const char *arch);
+cpuNodeData (virArch arch);
 
 extern virCPUCompareResult
 cpuGuestData(virCPUDefPtr host,
@@ -157,7 +158,7 @@ cpuUpdate   (virCPUDefPtr guest,
              const virCPUDefPtr host);
 
 extern int
-cpuHasFeature(const char *arch,
+cpuHasFeature(virArch arch,
               const union cpuData *data,
               const char *feature);
 
diff --git a/src/cpu/cpu_arm.c b/src/cpu/cpu_arm.c
index 2d005df..36c9db0 100644
--- a/src/cpu/cpu_arm.c
+++ b/src/cpu/cpu_arm.c
@@ -28,7 +28,7 @@
 
 #define VIR_FROM_THIS VIR_FROM_CPU
 
-static const char *archs[] = { "armv7l" };
+static const virArch archs[] = { VIR_ARCH_ARMV7L };
 
 static union cpuData *
 ArmNodeData(void)
diff --git a/src/cpu/cpu_generic.c b/src/cpu/cpu_generic.c
index 3a6ed6c..b10ff47 100644
--- a/src/cpu/cpu_generic.c
+++ b/src/cpu/cpu_generic.c
@@ -64,7 +64,8 @@ genericCompare(virCPUDefPtr host,
     unsigned int i;
     unsigned int reqfeatures;
 
-    if ((cpu->arch && STRNEQ(host->arch, cpu->arch)) ||
+    if (((cpu->arch != VIR_ARCH_NONE) &&
+         (host->arch != cpu->arch)) ||
         STRNEQ(host->model, cpu->model))
         return VIR_CPU_COMPARE_INCOMPATIBLE;
 
@@ -139,11 +140,11 @@ genericBaseline(virCPUDefPtr *cpus,
     }
 
     if (VIR_ALLOC(cpu) < 0 ||
-        !(cpu->arch = strdup(cpus[0]->arch)) ||
         !(cpu->model = strdup(cpus[0]->model)) ||
         VIR_ALLOC_N(features, cpus[0]->nfeatures) < 0)
         goto no_memory;
 
+    cpu->arch = cpus[0]->arch;
     cpu->type = VIR_CPU_TYPE_HOST;
 
     count = nfeatures = cpus[0]->nfeatures;
@@ -153,10 +154,11 @@ genericBaseline(virCPUDefPtr *cpus,
     for (i = 1; i < ncpus; i++) {
         virHashTablePtr hash;
 
-        if (STRNEQ(cpu->arch, cpus[i]->arch)) {
+        if (cpu->arch != cpus[i]->arch) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("CPUs have incompatible architectures: '%s' != '%s'"),
-                           cpu->arch, cpus[i]->arch);
+                           virArchToString(cpu->arch),
+                           virArchToString(cpus[i]->arch));
             goto error;
         }
 
diff --git a/src/cpu/cpu_powerpc.c b/src/cpu/cpu_powerpc.c
index e420ffb..ac10789 100644
--- a/src/cpu/cpu_powerpc.c
+++ b/src/cpu/cpu_powerpc.c
@@ -36,7 +36,7 @@
 
 #define VIR_FROM_THIS VIR_FROM_CPU
 
-static const char *archs[] = { "ppc64" };
+static const virArch archs[] = { VIR_ARCH_PPC64 };
 
 struct cpuPowerPC {
     const char *name;
@@ -417,7 +417,8 @@ static virCPUCompareResult
 PowerPCCompare(virCPUDefPtr host,
            virCPUDefPtr cpu)
 {
-    if ((cpu->arch && STRNEQ(host->arch, cpu->arch)) ||
+    if ((cpu->arch != VIR_ARCH_NONE &&
+         (host->arch != cpu->arch)) ||
         STRNEQ(host->model, cpu->model))
         return VIR_CPU_COMPARE_INCOMPATIBLE;
 
@@ -589,9 +590,10 @@ PowerPCBaseline(virCPUDefPtr *cpus,
         goto error;
     }
 
-    if (VIR_ALLOC(cpu) < 0 ||
-        !(cpu->arch = strdup(cpus[0]->arch)))
-        goto no_memory;
+    if (VIR_ALLOC(cpu) < 0)
+         goto no_memory;
+
+    cpu->arch = cpus[0]->arch;
     cpu->type = VIR_CPU_TYPE_GUEST;
     cpu->match = VIR_CPU_MATCH_EXACT;
 
@@ -610,8 +612,6 @@ PowerPCBaseline(virCPUDefPtr *cpus,
     if (!outputModel)
         VIR_FREE(cpu->model);
 
-    VIR_FREE(cpu->arch);
-
 cleanup:
     ppcModelFree(base_model);
     ppcMapFree(map);
diff --git a/src/cpu/cpu_s390.c b/src/cpu/cpu_s390.c
index 137c15f..ffbad03 100644
--- a/src/cpu/cpu_s390.c
+++ b/src/cpu/cpu_s390.c
@@ -29,7 +29,7 @@
 
 #define VIR_FROM_THIS VIR_FROM_CPU
 
-static const char *archs[] = { "s390", "s390x" };
+static const virArch archs[] = { VIR_ARCH_S390, VIR_ARCH_S390X };
 
 static union cpuData *
 s390NodeData(void)
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index ca8cd92..2001b99 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -40,7 +40,7 @@
 
 static const struct cpuX86cpuid cpuidNull = { 0, 0, 0, 0, 0 };
 
-static const char *archs[] = { "i686", "x86_64" };
+static const virArch archs[] = { VIR_ARCH_I686, VIR_ARCH_X86_64 };
 
 struct x86_vendor {
     char *name;
@@ -1165,22 +1165,23 @@ x86Compute(virCPUDefPtr host,
     enum compare_result result;
     unsigned int i;
 
-    if (cpu->arch != NULL) {
+    if (cpu->arch != VIR_ARCH_NONE) {
         bool found = false;
 
         for (i = 0; i < ARRAY_CARDINALITY(archs); i++) {
-            if (STREQ(archs[i], cpu->arch)) {
+            if (archs[i] == cpu->arch) {
                 found = true;
                 break;
             }
         }
 
         if (!found) {
-            VIR_DEBUG("CPU arch %s does not match host arch", cpu->arch);
+            VIR_DEBUG("CPU arch %s does not match host arch",
+                      virArchToString(cpu->arch));
             if (message &&
                 virAsprintf(message,
                             _("CPU arch %s does not match host arch"),
-                            cpu->arch) < 0)
+                            virArchToString(cpu->arch)) < 0)
                 goto no_memory;
             return VIR_CPU_COMPARE_INCOMPATIBLE;
         }
@@ -1643,9 +1644,10 @@ x86Baseline(virCPUDefPtr *cpus,
     if (!(base_model = x86ModelFromCPU(cpus[0], map, VIR_CPU_FEATURE_REQUIRE)))
         goto error;
 
-    if (VIR_ALLOC(cpu) < 0 ||
-        !(cpu->arch = strdup(cpus[0]->arch)))
+    if (VIR_ALLOC(cpu) < 0)
         goto no_memory;
+
+    cpu->arch = cpus[0]->arch;
     cpu->type = VIR_CPU_TYPE_GUEST;
     cpu->match = VIR_CPU_MATCH_EXACT;
 
@@ -1713,8 +1715,6 @@ x86Baseline(virCPUDefPtr *cpus,
     if (!outputVendor)
         VIR_FREE(cpu->vendor);
 
-    VIR_FREE(cpu->arch);
-
 cleanup:
     x86ModelFree(base_model);
     x86MapFree(map);
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index c9146c4..f6b53ca 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -805,14 +805,14 @@ qemuCapsInitCPU(virCapsPtr caps,
     union cpuData *data = NULL;
     virNodeInfo nodeinfo;
     int ret = -1;
-    const char *archstr = virArchToString(arch);
 
-    if (VIR_ALLOC(cpu) < 0
-        || !(cpu->arch = strdup(archstr))) {
+    if (VIR_ALLOC(cpu) < 0) {
         virReportOOMError();
         goto error;
     }
 
+    cpu->arch = arch;
+
     if (nodeGetInfo(NULL, &nodeinfo))
         goto error;
 
@@ -822,14 +822,14 @@ qemuCapsInitCPU(virCapsPtr caps,
     cpu->threads = nodeinfo.threads;
     caps->host.cpu = cpu;
 
-    if (!(data = cpuNodeData(archstr))
+    if (!(data = cpuNodeData(arch))
         || cpuDecode(cpu, data, NULL, 0, NULL) < 0)
         goto cleanup;
 
     ret = 0;
 
 cleanup:
-    cpuDataFree(archstr, data);
+    cpuDataFree(arch, data);
 
     return ret;
 
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 267dce7..2628f7d 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4358,10 +4358,10 @@ qemuBuildCpuArgStr(const virQEMUDriverPtr driver,
             virBufferAddLit(&buf, "host");
         } else {
             if (VIR_ALLOC(guest) < 0 ||
-                !(guest->arch = strdup(host->arch)) ||
                 (cpu->vendor_id && !(guest->vendor_id = strdup(cpu->vendor_id))))
                 goto no_memory;
 
+            guest->arch = host->arch;
             if (cpu->match == VIR_CPU_MATCH_MINIMUM)
                 preferred = host->model;
             else
@@ -8127,13 +8127,13 @@ qemuParseCommandLineCPU(virDomainDefPtr dom,
             union cpuData *cpuData = NULL;
             int ret;
 
-            ret = cpuEncode("x86_64", cpu, NULL, &cpuData,
+            ret = cpuEncode(VIR_ARCH_X86_64, cpu, NULL, &cpuData,
                             NULL, NULL, NULL, NULL);
             if (ret < 0)
                 goto error;
 
-            is_32bit = (cpuHasFeature("x86_64", cpuData, "lm") != 1);
-            cpuDataFree("x86_64", cpuData);
+            is_32bit = (cpuHasFeature(VIR_ARCH_X86_64, cpuData, "lm") != 1);
+            cpuDataFree(VIR_ARCH_X86_64, cpuData);
         } else if (model) {
             is_32bit = STREQ(model, "qemu32");
         }
diff --git a/src/vmware/vmware_conf.c b/src/vmware/vmware_conf.c
index 33100fb..bada4a5 100644
--- a/src/vmware/vmware_conf.c
+++ b/src/vmware/vmware_conf.c
@@ -63,7 +63,6 @@ vmwareCapsInit(void)
     virCapsGuestPtr guest = NULL;
     virCPUDefPtr cpu = NULL;
     union cpuData *data = NULL;
-    const char *hostarch = NULL;
 
     if ((caps = virCapabilitiesNew(virArchFromHost(),
                                    0, 0)) == NULL)
@@ -91,8 +90,7 @@ vmwareCapsInit(void)
         goto error;
     }
 
-    hostarch = virArchToString(caps->host.arch);
-    if (!(cpu->arch = strdup(hostarch))) {
+    if (!(cpu->arch = caps->host.arch)) {
         virReportOOMError();
         goto error;
     }
@@ -109,9 +107,9 @@ vmwareCapsInit(void)
      *  - Host CPU is x86_64 with virtualization extensions
      */
     if (caps->host.arch == VIR_ARCH_X86_64 ||
-        (cpuHasFeature(hostarch, data, "lm") &&
-         (cpuHasFeature(hostarch, data, "vmx") ||
-          cpuHasFeature(hostarch, data, "svm")))) {
+        (cpuHasFeature(caps->host.arch, data, "lm") &&
+         (cpuHasFeature(caps->host.arch, data, "vmx") ||
+          cpuHasFeature(caps->host.arch, data, "svm")))) {
 
         if ((guest = virCapabilitiesAddGuest(caps,
                                              "hvm",
@@ -129,7 +127,7 @@ vmwareCapsInit(void)
 
 cleanup:
     virCPUDefFree(cpu);
-    cpuDataFree(hostarch, data);
+    cpuDataFree(caps->host.arch, data);
 
     return caps;
 
-- 
1.7.11.7


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]