1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143

base / win / variant_vector.h [blame]

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_WIN_VARIANT_VECTOR_H_
#define BASE_WIN_VARIANT_VECTOR_H_

#include <objbase.h>

#include <oleauto.h>

#include <type_traits>
#include <utility>
#include <vector>

#include "base/base_export.h"
#include "base/check.h"
#include "base/logging.h"
#include "base/win/scoped_variant.h"
#include "base/win/variant_conversions.h"

namespace base {
namespace win {

// This class has RAII semantics and is used to build a vector for a specific
// OLE VARTYPE, and handles converting the data to a VARIANT or VARIANT
// SAFEARRAY. It can be populated similarly to a STL vector<T>, but without the
// compile-time requirement of knowing what element type the VariantVector will
// store. The VariantVector only allows one variant type to be stored at a time.
//
// This class can release ownership of its contents to a VARIANT, and will
// automatically allocate + populate a SAFEARRAY as needed or when explicitly
// requesting that the results be released as a SAFEARRAY.
class BASE_EXPORT VariantVector final {
 public:
  VariantVector();
  VariantVector(VariantVector&& other);
  VariantVector& operator=(VariantVector&& other);
  VariantVector(const VariantVector&) = delete;
  VariantVector& operator=(const VariantVector&) = delete;
  ~VariantVector();

  bool operator==(const VariantVector& other) const;
  bool operator!=(const VariantVector& other) const;

  // Returns the variant type for data stored in the VariantVector.
  VARTYPE Type() const { return vartype_; }

  // Returns the number of elements in the VariantVector.
  size_t Size() const { return vector_.size(); }

  // Returns whether or not there are any elements.
  bool Empty() const { return vector_.empty(); }

  // Resets VariantVector to its default state, releasing any managed content.
  void Reset();

  // Helper template method for selecting the correct |Insert| call based
  // on the underlying type that is expected for a VARTYPE.
  template <VARTYPE ExpectedVartype,
            std::enable_if_t<ExpectedVartype != VT_BOOL, int> = 0>
  void Insert(
      typename internal::VariantConverter<ExpectedVartype>::Type value) {
    if (vartype_ == VT_EMPTY)
      vartype_ = ExpectedVartype;
    AssertVartype<ExpectedVartype>();
    ScopedVariant scoped_variant;
    scoped_variant.Set(value);
    vector_.push_back(std::move(scoped_variant));
  }

  // Specialize VT_BOOL to accept a bool type instead of VARIANT_BOOL,
  // this is to make calling insert with VT_BOOL safer.
  template <VARTYPE ExpectedVartype,
            std::enable_if_t<ExpectedVartype == VT_BOOL, int> = 0>
  void Insert(bool value) {
    if (vartype_ == VT_EMPTY)
      vartype_ = ExpectedVartype;
    AssertVartype<ExpectedVartype>();
    ScopedVariant scoped_variant;
    scoped_variant.Set(value);
    vector_.push_back(std::move(scoped_variant));
  }

  // Specialize VT_DATE because ScopedVariant has a separate SetDate method,
  // this is because VT_R8 and VT_DATE share the same underlying type.
  template <>
  void Insert<VT_DATE>(
      typename internal::VariantConverter<VT_DATE>::Type value) {
    if (vartype_ == VT_EMPTY)
      vartype_ = VT_DATE;
    AssertVartype<VT_DATE>();
    ScopedVariant scoped_variant;
    scoped_variant.SetDate(value);
    vector_.push_back(std::move(scoped_variant));
  }

  // Populates a VARIANT based on what is stored, transferring ownership
  // of managed contents.
  // This is only valid when the VariantVector is empty or has a single element.
  // The VariantVector is then reset.
  VARIANT ReleaseAsScalarVariant();

  // Populates a VARIANT as a SAFEARRAY, even if there is only one element.
  // The VariantVector is then reset.
  VARIANT ReleaseAsSafearrayVariant();

  // Lexicographical comparison between a VariantVector and a VARIANT.
  // The return value is 0 if the variants are equal, 1 if this object is
  // greater than |other|, -1 if it is smaller.
  int Compare(const VARIANT& other, bool ignore_case = false) const;

  // Lexicographical comparison between a VariantVector and a SAFEARRAY.
  int Compare(SAFEARRAY* safearray, bool ignore_case = false) const;

  // Lexicographical comparison between two VariantVectors.
  int Compare(const VariantVector& other, bool ignore_case = false) const;

 private:
  // Returns true if the current |vartype_| is compatible with |ExpectedVartype|
  // for inserting into |vector_|.
  template <VARTYPE ExpectedVartype>
  void AssertVartype() const {
    DCHECK(
        internal::VariantConverter<ExpectedVartype>::IsConvertibleTo(vartype_))
        << "Type mismatch, " << ExpectedVartype << " is not convertible to "
        << Type();
  }

  // Creates a SAFEARRAY and populates it with teh values held by each VARIANT
  // in |vector_|, transferring ownership to the new SAFEARRAY.
  // The VariantVector is reset when successful.
  template <VARTYPE ElementVartype>
  SAFEARRAY* CreateAndPopulateSafearray();

  VARTYPE vartype_ = VT_EMPTY;
  std::vector<ScopedVariant> vector_;
};

}  // namespace win
}  // namespace base

#endif  // BASE_WIN_VARIANT_VECTOR_H_