summaryrefslogtreecommitdiffstats
path: root/intl/components/src/MeasureUnit.h
blob: 8a8cf1629a68eb9da38c0a4ddc2471865b4512f2 (plain)
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
144
145
146
147
148
149
150
151
152
153
154
155
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef intl_components_MeasureUnit_h_
#define intl_components_MeasureUnit_h_

#include "mozilla/Assertions.h"
#include "mozilla/intl/ICU4CGlue.h"
#include "mozilla/intl/ICUError.h"
#include "mozilla/Result.h"
#include "mozilla/Span.h"
#include "mozilla/UniquePtr.h"

#include <iterator>
#include <stddef.h>
#include <stdint.h>
#include <utility>

struct UResourceBundle;

namespace mozilla::intl {

/**
 * This component is a Mozilla-focused API for working with measurement units in
 * internationalization code. It is used in coordination with other operations
 * such as number formatting.
 */
class MeasureUnit final {
  class UResourceBundleDeleter {
   public:
    void operator()(UResourceBundle* aPtr);
  };

  using UniqueUResourceBundle =
      UniquePtr<UResourceBundle, UResourceBundleDeleter>;

 public:
  MeasureUnit() = delete;

  class Enumeration final {
    // Resource bundle for the root locale.
    UniqueUResourceBundle mRootLocale = nullptr;

    // Resource bundle for the root locale's "units" resource table.
    UniqueUResourceBundle mUnits = nullptr;

    // The overall amount of available units.
    int32_t mUnitsSize = 0;

   public:
    Enumeration(UniqueUResourceBundle aRootLocale,
                UniqueUResourceBundle aUnits);

    class Iterator {
     public:
      // std::iterator traits.
      using iterator_category = std::input_iterator_tag;
      using value_type = SpanResult<char>;
      using difference_type = ptrdiff_t;
      using pointer = value_type*;
      using reference = value_type&;

     private:
      const Enumeration& mEnumeration;

      // Resource bundle to a measurement type within the "units" table.
      //
      // Measurement types describe various categories, like "area", "length",
      // or "mass".
      UniqueUResourceBundle mType = nullptr;

      // Resource bundle to a specific subtype within the type table.
      //
      // Measurement subtypes describe concrete measure units, like "acre",
      // "meter", or "kilogram".
      UniqueUResourceBundle mSubtype = nullptr;

      // The next position within the "units" table.
      int32_t mUnitsPos = 0;

      // The overall amount of types within the |mType| table.
      int32_t mTypeSize = 0;

      // The next position within the |mType| table.
      int32_t mTypePos = 0;

      // Flag set when an ICU error has occurred. All further operations on this
      // iterator will return an error result when this flag is set.
      bool mHasError = false;

      void advance();

     public:
      Iterator(const Enumeration& aEnumeration, int32_t aUnitsPos)
          : mEnumeration(aEnumeration), mUnitsPos(aUnitsPos) {
        advance();
      }

      Iterator& operator++() {
        advance();
        return *this;
      }

      // The post-increment operator would return an invalid iterator, so it's
      // not implemented.
      Iterator operator++(int) = delete;

      bool operator==(const Iterator& aOther) const {
        // It's an error to compare an iterator against an iterator from a
        // different enumeration.
        MOZ_ASSERT(&mEnumeration == &aOther.mEnumeration);

        return mUnitsPos == aOther.mUnitsPos && mTypeSize == aOther.mTypeSize &&
               mTypePos == aOther.mTypePos && mHasError == aOther.mHasError;
      }

      bool operator!=(const Iterator& aOther) const {
        return !(*this == aOther);
      }

      value_type operator*() const;
    };

    friend class Iterator;

    // std::iterator begin() and end() methods.

    /**
     * Return an iterator pointing to the start of the "units" table.
     */
    Iterator begin() { return Iterator(*this, 0); }

    /**
     * Return an iterator pointing to the end of the "units" table.
     */
    Iterator end() { return Iterator(*this, mUnitsSize); }

    /**
     * Create a new measurement unit enumeration.
     */
    static Result<Enumeration, ICUError> TryCreate();
  };

  /**
   * Return an enumeration over all available measurement units.
   */
  static Result<Enumeration, ICUError> GetAvailable() {
    return Enumeration::TryCreate();
  }
};

}  // namespace mozilla::intl

#endif